在js中雙重循環,代碼如下:
for(let i =0; i < l1;i++){for(let j=0; j< l2;j++){// todo...}
}
以上代碼在匯編中是如何實現的呢.
mov cx, 4
s: mov ax,1loop s
assume cs:codesg, ds:datasgdatasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg endscodesg segment
start: mov ax, datasgmov ds, axmov bx, 0 ; 用BX來定位行mov cx, 4s0: mov si, 0 ; 用si來定位列mov cx, 3s: mov al, [bx+si]and al, 11011111bmov [bx+si], alinc siloop s ; 此時的 cx 已經為0add bx, 16loop s0 ; cx = cx -1 , 再判斷 cx 為是否為0mov ax, 4c00hint 21hend codesg
end start
原因如下: 每當執行 loop 語句時, 實際是執行 cx = cx -1 然后判斷 cx 是否為0. 于是在內層循環后(loop s), cx =0 , 然后再到 loop s0時,此時先執行 cx = cx - 1, 即此時 cx = FFFF 因此會陷入死循環 改進辦法.用寄存器dx來保存進入內層循環的cx,然后再內存循環結束時,將寄存器dx中的值賦給cx
start: mov ax, datasgmov ds, axmov bx, 0mov cx, 4s0: mov dx, cxmov si, 0mov cx, 3s: mov al, [bx+si]and al, 11011111bmov [bx+si], alinc siloop sadd bx, 16mov cx, dxloop s0mov ax, 4c00hint 21h
以上方法可以解決兩層循環的問題,但是CPU中的寄存器畢竟是有限的,當循環次數多的時候,寄存器將不夠用. 考慮到內存,可以將寄存器cx的值存入內存中.然后在內存循環結束后,在從內存中讀取值給cx
assme cs:codesg, ds: datasgdatasg segment
; 其他代碼略
dw 0 ; 定義一個字單元, 用來保存cx
datasg endscodesg segment
start: mov ax, datasgmov ds, ax ; 匯編中用ds來定位數據地址mov bx, 0 ; 偏移量為0mov cx, 4 ; 外層循環為4s0: mov ds:[40H], cx ; 將外層循環的次數保存到內存datasg:40H單元中mov si, 0mov cx, 3s: mov al, [bx+si]and al, 11011111bmov [bx+si], alinc siloop sadd bx, 16 ; 移到下一個字單元mov cx, ds:[40H] ; 從內存中取出當前循環的次數loop s0mov ax, 4c00hint 21h
end codesg
end start
以上方法可以解決CPU中寄存器不夠用的情況,但對于保存的多個數據,程序猿們必須要記住數據保存在哪個內存單元中.當代碼量大的時候,需要寫很多注釋,也不利于閱讀與維護 看VC++ 6.0編譯器是如何處理的 通過反編譯,查看匯編源碼可以發現. 在遇到函數時,編譯器將當前環境push進一個棧中,當執行完畢,將棧中的環境pop出來 于是上面的代碼可以改為如下:
stack segment ; 棧空間dw 0,0,0,0,0,0,0,0 ; 16字節(根據需要定)
stack endscodesg segment
start: mov ax, stacksgmov ss, axmov sp, 16 ; 匯編中ss 指向棧端, sp代表偏移量為16mov ax, datasgmov ds, axmov bx, 0mov cx, 4s0: push cxmov si,0mov cx, 3s: mov al, [bx+si]and al, 11011111bmov [bx+si], alinc siloop sadd bx, 16pop cxloop s0mov ax, 4c00hint 21h
codesg ends
end start