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結構更好。