教你用彙編分析C++之循環邏輯

循環是我們編程中遇到的另外一項重要技術。通過反覆的迭代運算,我們可以獲取想要的任何結果。當然這種迭代是有基本條件的,或是以時間為條件的,或是以空間為條件的,或者是某一種外來交互作為條件的。循環的方式有很多種,但是常用的還是:while、for、do-while、goto這幾種。很多公司的項目都不喜歡goto,這其中倒不是說goto不好,主要是goto的隨意性太大,一旦用的不好,就會降低代碼的可讀性,反而影響其他人的工作效率。

(1)do-while為什麼先執行,後判斷?

老規矩,我們還是先看代碼示例再說:


21: int m = 10;
00401638 mov dword ptr [ebp-4],0Ah
22: do {
23: printf("%d\n", m);
0040163F mov eax,dword ptr [ebp-4]
00401642 push eax
00401643 push offset string "%d\n" (0046f01c)
00401648 call printf (00420fb0)
0040164D add esp,8
24: m ++;
00401650 mov ecx,dword ptr [ebp-4]
00401653 add ecx,1
00401656 mov dword ptr [ebp-4],ecx
25: }while(m < 10);
00401659 cmp dword ptr [ebp-4],0Ah
0040165D jl process+1Fh (0040163f)
如果換成while呢?
21: int m = 10;
00401638 mov dword ptr [ebp-4],0Ah
22: while(m < 20)
0040163F cmp dword ptr [ebp-4],14h
00401643 jge process+41h (00401661)
23: {
24: printf("%d\n", m);
00401645 mov eax,dword ptr [ebp-4]
00401648 push eax
00401649 push offset string "%d\n" (0046f01c)
0040164E call printf (00420fb0)
00401653 add esp,8
25: m ++;
00401656 mov ecx,dword ptr [ebp-4]
00401659 add ecx,1
0040165C mov dword ptr [ebp-4],ecx
26: }
0040165F jmp process+1Fh (0040163f)
27: }
其實,上面的代碼表現已經很明顯了。do-while的時候,模塊上來先進行運算,然後再判斷數據範圍的大小;while就不一樣,上來就進行判斷,判斷成功就繼續運行,否則就退出循環模塊,如果是for的情況呢?

21: for(int m = 10; m < 20; m++)
00401638 mov dword ptr [ebp-4],0Ah
0040163F jmp process+2Ah (0040164a)
00401641 mov eax,dword ptr [ebp-4]
00401644 add eax,1
00401647 mov dword ptr [ebp-4],eax
0040164A cmp dword ptr [ebp-4],14h
0040164E jge process+4Ch (0040166c)
22: {
23: printf("%d\n", m);
00401650 mov ecx,dword ptr [ebp-4]
00401653 push ecx
00401654 push offset string "%d\n" (0046f01c)
00401659 call printf (00420fc0)
0040165E add esp,8
24: m ++;
00401661 mov edx,dword ptr [ebp-4]
00401664 add edx,1
00401667 mov dword ptr [ebp-4],edx
25: }
0040166A jmp process+21h (00401641)

我們發現,其實for和上面的while,do-while有點小區別。在m第一次賦值的時候,並不進行加1處理,而是直接跳到地址0x40164a處運行,判斷m數值和20進行判斷。判斷成功,則跳入循環模塊,否則越過循環模塊。那麼,在循環處理結束後呢?也就是m++後,循環模塊是怎麼處理的?我們發現代碼又回到了0x00401641處處理。但是這裡並不是整個循環模塊開始出的代碼,而是對m進行自增處理。完成自增後,繼續判斷,下面的流程和第一次一樣,不再贅述。

(2)多重循環怎麼跳出來?

很多朋友編碼的時候都有這樣的一個困擾,有的時候希望在多層循環中尋找某一個條件的變量,但是在找到特定變量後,希望趕快退出循環。我們應該怎麼做呢,下面是我個人的做法,僅供大家參考。


int flag = 0;
for(int m = 1; m < 20 && !flag; m++)
{
for(int n = 1; n < 20 && !flag; n++)
{
for(int t = 1; t < 20 && !flag; t++)
{
if(/* special conditions are satisfied */)
flag = 1;
}
}
}


(3)while(1)是否有其他的表示方法?


int flag = 0;
for(;;) {
/* code segment */
}

do{
/* code segment */
}while(1);

loop:
{
/* code segment */
}

if(!flag)
goto loop;

總結:

其實,循環中還有很多的細節需要處理,你比如說:

(1)循環的時候請務必填上程序終止的條件

(2)循環的時候注意8位char和32和int之間的區別,務必不要死循環

(3)字符的循環務必注意‘\0’

(4)不要把循環、判斷合二為1,給你的同事留條活路,不要以為while(*dst ++ = *src ++);這樣寫代碼很帥

(5)務必注意自己的返回值是你需要的那個地址,還是前一個地址,還是下一個地址

(6)不要在for(;;)中添加額外的語句,加的越多,風險越多


分享到:


相關文章: