在我們平常的程式設計當中,用於判斷的地方很多,但主要有下面三種方式: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...