if else 和 switch的效率

 switch...case與if...else的根本區別在於,switch...case會生成一個跳轉表來指示實際的case分支的地址,而這個跳轉表的索引號與switch變量的值是相等的。從而,switch...case不用像if...else那樣遍歷條件分支直到命中條件,而只需訪問對應索引號的表項從而到達定位分支的目的。
具體地說,switch...case會生成一份大小(表項數)爲最大case常量+1的跳錶,程序首先判斷switch變量是否大於最大case 常量,若大於,則跳到default分支處理;否則取得索引號爲switch變量大小的跳錶項的地址(即跳錶的起始地址+表項大小*索引號),程序接着跳到此地址執行,到此完成了分支的跳轉。
int main()
{
 unsigned int i,j;
 i=3;
 switch (i)
 {
  case 0:
  j=0;
  break;
  case 1:
  j=1;
  break;
  case 2:
  j=2;
  break;
  case 3:
  j=3;
  break;
  case 4:
  j=4;
  break;
  default:
  j=10;
  break;
 }


}

用gcc編譯器,生成彙編代碼(不開編譯器優化)
 .file "shiyan.c"
 .text
.globl main
 .type main, @function
main:
 leal 4(%esp), %ecx
 andl $-16, %esp
 pushl -4(%ecx)
 pushl %ebp
 movl %esp, %ebp
 pushl %ecx
 subl $20, %esp
 movl $3, -8(%ebp)
 cmpl $4, -8(%ebp)
 ja .L2
 movl -8(%ebp), %eax
 sall $2, %eax
 movl .L8(%eax), %eax
 jmp *%eax
 .section .rodata
 .align 4
 .align 4
.L8:
 .long .L3
 .long .L4
 .long .L5
 .long .L6
 .long .L7
 .text
.L3:
 movl $0, -12(%ebp)
 jmp .L11
.L4:
 movl $1, -12(%ebp)
 jmp .L11
.L5:
 movl $2, -12(%ebp)
 jmp .L11
.L6:
 movl $3, -12(%ebp)
 jmp .L11
.L7:
 movl $4, -12(%ebp)
 jmp .L11
.L2:
 movl $10, -12(%ebp)
.L11:
 addl $20, %esp
 popl %ecx
 popl %ebp
 leal -4(%ecx), %esp
 ret
 .size main, .-main
 .ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
 .section .note.GNU-stack,"",@progbits

由此看來,switch有點以空間換時間的意思,而事實上也的確如此。
1.當分支較多時,當時用switch的效率是很高的。因爲switch是隨機訪問的,就是確定了選擇值之後直接跳轉到那個特定的分支,但是if。。else是遍歷所以得可能值,知道找到符合條件的分支。如此看來,switch的效率確實比ifelse要高的多。
2.由上面的彙編代碼可知道,switch...case佔用較多的代碼空間,因爲它要生成跳錶,特別是當case常量分佈範圍很大但實際有效值又比較少的情況,switch...case的空間利用率將變得很低。

3.switch...case只能處理case爲常量的情況,對非常量的情況是無能爲力的。例如 if (a > 1 && a < 100),是無法使用switch...case來處理的。所以,switch只能是在常量選擇分支時比ifelse效率高,但是ifelse能應用於更多的場合,ifelse比較靈活。

switch和if-else相比,由於使用了Binary Tree算法,絕大部分情況下switch會快一點,除非是if-else的第一個條件就爲true. 
在實際開發中  沒有人會去用很多很多else if的 
都是用 switch case 的  後者比較清晰  給人感覺就是一個腦子很清楚的人寫出來的東西 

編譯器編譯switch與編譯if...else...不同。不管有多少case,都直接跳轉,不需逐個比較查詢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章