用彙編的眼光看C (之判斷流程)04

2022-03-24 15:23:58 字數 2984 閱讀 6005

在我們平常的程式設計當中,用於判斷的地方很多,但主要有下面三種方式:if-else;switch;?:。其中最後一種方式在本質上和if-else是 一樣的。switch和if-else其實也一樣,如果我們把switch改成if(...) {} else if(...) {} else {},那麼你實現的效果和switch實際差不多,熟悉的朋友都會有這樣的體驗。或許有的朋友還是不太相信,大家可以自己用寫例項比較看一下。

(1) switch中的break重要嗎?

[cpp]view plain

copy

21:       

intm = 10;  

004017a8   mov         dword ptr [ebp-4],0ah  

22:       switch

(m)  

23:         

35:       return

;  36:   }  

上面的彙編**說明了有break的時候,函式是怎麼編譯的。我們看到從位址0x4017af處, cpu開始集中對m進行判斷。首先,m的資料被賦值到eax,然後eax拷貝到堆疊【ebp-8】的記憶體當中。接著開始比較資料10,即16進製制0a,如 果兩者相等,**跳轉到0x4017c3處理;但是如果不相等呢,那麼指令會按照原來的排列順序繼續向下走,和11繼續比較,如果比較成功,那麼就會到地 址0x4017d2處執行,如果都不相等,那麼只好跳出switch模組,到位址0x4017df處執行了。前面我們說到,如果資料和10或者11比較成 功的話,那麼就會跳轉到相應的case語句處繼續執行,可是比較結束後,還會跳轉到原來的位置嗎?彙編**告訴我們,他們不會。因為case比較結束後, 也要到位址ox4017df處報到。

如果這裡case10後面沒有break呢?情況會不會不一樣呢?

[cpp]view plain

copy

004017a8   mov         dword ptr [ebp-4],0ah  

22:       switch

(m)  

23:         

34:       return

;  35:   }  

我們在case10後面取消了break語句。和原來的情形稍有不同,我們發現case10在執行了printf函式之後,並沒有跳出當前的 switch模組,而是繼續執行case11的語句。所以在輸出結果的時候,你會發現ten和eleven都有列印。看了這樣清晰的流程之後,相信你對 break的重要性又有了新的認識。在彙編面前,一切都一目了然。

(2)if中的&&和||是怎麼運算的?

同樣,我們可以看下面一段示例。

[cpp]view plain

copy

21:       

intm = 10;  

004017a8   mov         dword ptr [ebp-4],0ah  

22:       int

n = 0;  

004017af   mov         dword ptr [ebp-8],0  

23:  

24:       if

(m == 10 && n == 0)  

004017b6   cmp         dword ptr [ebp-4],0ah  

004017ba   jne         process+3fh (004017cf)  

004017bc   cmp         dword ptr [ebp-8],0  

004017c0   jne         process+3fh (004017cf)  

25:         

28:  

29:       if

(m == 10 || n == 0)  

004017cf   cmp         dword ptr [ebp-4],0ah  

004017d3   je          process+4bh (004017db)  

004017d5   cmp         dword ptr [ebp-8],0  

004017d9   jne         process+58h (004017e8)  

30:         

&&在c語言中是與的意思,而||是或的意思。與就是說,兩者均為真;而或的意思是兩方中一方為真即可。這在對應的彙編的語句上面也体 現得淋漓盡致。首先我們看與的情形。從位址0x4017b6處地指令,我們發現首先比較的是m資料,然後比較的是n資料,這可以從他們在堆疊中的偏移值可 以看出來。如果m和10比較,那麼下面才有n和0比較的機會,一旦比較失敗,就會跳轉到位址0x4017cf處執行,跳出當前的判斷模組。n和0比較也一 樣,只有兩者都比較成功,才有機會進入位址0x4017c2處執行,列印&&。和與對應的是或,我們發現位址0x4017cf處開始比較 的也是資料m,其次才是資料n。和與不同,m資料和n資料只要由一方成功,就會跳轉到位址0x4017db處執行。只有兩者都為假,才會跳出當前的模組。 所以說,兩個jne構成了與的基礎,乙個je和乙個jne構成了或的基石。大家可以自己試試看如果&&的選項和||的選項不斷進行疊加的 時候會出現怎樣的情形?試試看。

總結:

if-else這種二分判斷結構其實在現在的程式設計中特別重要,也特別基礎。有乙個關於二分法最顯著的**就是在順序資料中進行二分查詢。如果有興趣的話,自己可以動筆試試?在這裡,我有幾個建議:

(1)確保函式輸入的索引範圍有序 (start < end)

(2)在計算中間點的時候注意不要範圍溢位 (middle = start + (end - start) >> 1)

(3)考慮把你的函式修改成通用的二分法查詢函式(可以考慮用const void*和函式指標)

【預告: 下面一片博文的內容是用彙編的眼光看c++之迴圈判斷】

用彙編的眼光看C (之退出流程)

無論是在判斷還是在迴圈的過程中,通常在遇到合適的條件的時候就會退出相應的模組。跳出模組執行的方式很多,break,continue,return都可以。下面我們就可以分別對他們進行將介紹。1 continue只能用於迴圈,而break迴圈 判斷都可以應用。兩者有什麼區別呢?view plain 21...

用彙編的眼光看C (之退出流程)

無論是在判斷還是在迴圈的過程中,通常在遇到合適的條件的時候就會退出相應的模組。跳出模組執行的方式很多,break,continue,return都可以。下面我們就可以分別對他們進行將介紹。1 continue只能用於迴圈,而break迴圈 判斷都可以應用。兩者有什麼區別呢?21 for int m ...

用彙編的眼光看C (之退出流程)

無論是在判斷還是在迴圈的過程中,通常在遇到合適的條件的時候就會退出相應的模組。跳出模組執行的方式很多,break,continue,return都可以。下面我們就可以分別對他們進行將介紹。1 continue只能用於迴圈,而break迴圈 判斷都可以應用。兩者有什麼區別呢?cpp view plai...