1.switch...case結構的彙編表示
寫入switch...case結構的代碼:
int fun(char c) { char res; switch(c) { case 'a': res='a'; break; case 'e': res='e'; break; case 'i': res='i'; break; case 'o': res='o'; break; case 'u': res='u'; break; default: res=' '; }
用gcc產生的彙編代碼是:
00000000 <fun>: 0:55 push %ebp 1:89 e5 mov %esp,%ebp 3:83 ec 14 sub $0x14,%esp 6:8b 45 08 mov 0x8(%ebp),%eax 9:88 45 ec mov %al,-0x14(%ebp) c:0f be 45 ec movsbl -0x14(%ebp),%eax 10:83 e8 61 sub $0x61,%eax 13:83 f8 14 cmp $0x14,%eax 16:77 27 ja 3f <fun+0x3f> 18:8b 04 85 00 00 00 00 mov 0x0(,%eax,4),%eax 1f:ff e0 jmp *%eax 21:c6 45 ff 61 movb $0x61,-0x1(%ebp) 25:eb 1c jmp 43 <fun+0x43> 27:c6 45 ff 65 movb $0x65,-0x1(%ebp) 2b:eb 16 jmp 43 <fun+0x43> 2d:c6 45 ff 69 movb $0x69,-0x1(%ebp) 31:eb 10 jmp 43 <fun+0x43> 33:c6 45 ff 6f movb $0x6f,-0x1(%ebp) 37:eb 0a jmp 43 <fun+0x43> 39:c6 45 ff 75 movb $0x75,-0x1(%ebp) 3d:eb 04 jmp 43 <fun+0x43> 3f:c6 45 ff 20 movb $0x20,-0x1(%ebp) 43:0f be 45 ff movsbl -0x1(%ebp),%eax 47:c9 leave 48:c3 ret
電腦中處理switch...case結構時,會產生跳轉表,根據變數的取值跳轉到合適的分支。在上面的例子中,變數c存放在ebp位移8位元組的位置,它首先減去97,如果大於20則跳轉到預設分支。在執行完對應的分支後,每個分支後都有jmp43語句用於跳轉到函數的結尾。
2.if...else語句的彙編表示
上面的代碼寫成if...else的形式,產生的彙編代碼是:
00000000 <fun>: 0:55 push %ebp 1:89 e5 mov %esp,%ebp 3:83 ec 14 sub $0x14,%esp 6:8b 45 08 mov 0x8(%ebp),%eax 9:88 45 ec mov %al,-0x14(%ebp) c:80 7d ec 61 cmpb $0x61,-0x14(%ebp) 10:75 06 jne 18 <fun+0x18> 12:c6 45 ff 61 movb $0x61,-0x1(%ebp) 16:eb 34 jmp 4c <fun+0x4c> 18:80 7d ec 65 cmpb $0x65,-0x14(%ebp) 1c:75 06 jne 24 <fun+0x24> 1e:c6 45 ff 65 movb $0x65,-0x1(%ebp) 22:eb 28 jmp 4c <fun+0x4c> 24:80 7d ec 69 cmpb $0x69,-0x14(%ebp) 28:75 06 jne 30 <fun+0x30> 2a:c6 45 ff 69 movb $0x69,-0x1(%ebp) 2e:eb 1c jmp 4c <fun+0x4c> 30:80 7d ec 6f cmpb $0x6f,-0x14(%ebp) 34:75 06 jne 3c <fun+0x3c> 36:c6 45 ff 6f movb $0x6f,-0x1(%ebp) 3a:eb 10 jmp 4c <fun+0x4c> 3c:80 7d ec 75 cmpb $0x75,-0x14(%ebp) 40:75 06 jne 48 <fun+0x48> 42:c6 45 ff 75 movb $0x75,-0x1(%ebp) 46:eb 04 jmp 4c <fun+0x4c> 48:c6 45 ff 20 movb $0x20,-0x1(%ebp) 4c:0f be 45 ff movsbl -0x1(%ebp),%eax 50:c9 leave 51:c3 ret
可見,如果輸入了字元a,這個程式將不需要跳轉,這時if...else的效率要高於switch...case.如果是輸入了字元o或者u,程式將多次跳轉,程式的分支變多時,必然會導致效率降低。
3.switch...case語句和if...else效率比較
這裡不考慮編譯器的最佳化和條件傳送(條件傳送介紹),僅僅從跳轉次數來比較兩者的效率。
switch...case結構中有跳轉表,輸入的字元只要經過一次比較就可以正確的找到跳轉分支,所以平均情況下跳轉次數為1.
if...else結構如果有n個分支,分別記為n0,n1,n2,n3,...n(i-1),每個分支出現的機率假設未pi,分別為p0,p1,p2,p3,...p(i-1)。執行第一分支前不需要跳轉,其它分支均需要跳轉,執行第二個分支之前需要跳轉一次,第三個分支需要跳轉兩次...需要跳轉平均跳轉的次數s為:
如果>1,則此時if...case的效率是小於switch...case的,如果它的值小於1,此時if...else的效率高於switch...case。
假設if...else分支的每個分支出現的機率相同,即1/n,上面的跳轉次數的期望值可以改寫為:。
如果n=3,則期望的跳轉次數為1,剛好與switch...case相同。由此,如果選擇分支大於3的時候,選用switch...case結構效率會更高一些,而小於3時,選用if...else結構更好。
總結:在選擇分支較多時,選用switch...case結構會提高程式的效率,但switch不足的地方在於只能處理字元或者數字類型的變數,if...else結構更加靈活一些,if...else結構可以用於判斷運算式是否成立,比如if(a+b>c),if...else的應用範圍更廣,switch...case結構在某些情況下可以替代if...else結構。