if-else和switch的效率问题

来源:互联网 发布:sql offset分页 编辑:程序博客网 时间:2024/04/28 12:51

(环境:VC++6.0    操作系统:Windows XP SP3)
以前以为if-else和switch的效率差不多,用switch能实现的功能,用if-else实现都一样,只是写法有区别而已,其实这两个结构还是有比较大的区别的,switch用的是一个静态查找表,表中存的是各个case句的行号。下面用一个有if-else和switch的例子看一下就知道了:
C++源程序:
void main()
{
int x;
int y = 0;
switch(x)
{
case 1:
  y++;
  break;
case 2:
  y++;
  break;
case 3:
  y++;
  break;
case 6:
  y++;
  break;
case 7:
  y++;
  break;
default:
  y++;
  break;
}
if(x == 1)
{
  y++;
}
else if(x == 2)
{
  y++;
}
else if(x == 3)
{
  y++;
}
else if(x == 6)
{
  y++;
}
else if(x == 7)
{
  y++;
}
else
{
  y++;
}
}
if-else块和switch块实现功能一样,下面是其对应的汇编语句:
1:    #include <stdio.h>
2:
3:    void main()
4:    {
0040D3F0   push        ebp
0040D3F1   mov         ebp,esp
0040D3F3   sub         esp,4Ch
0040D3F6   push        ebx
0040D3F7   push        esi
0040D3F8   push        edi
0040D3F9   lea         edi,[ebp-4Ch]
0040D3FC   mov         ecx,13h
0040D401   mov         eax,0CCCCCCCCh
0040D406   rep stos    dword ptr [edi]
5:        int x = 0;
0040D408   mov         dword ptr [ebp-4],0      ;给x初始化


6:        int y = 0;
0040D40F   mov         dword ptr [ebp-8],0      ;给y初始化
7:        switch(x)
8:        {
0040D416   mov         eax,dword ptr [ebp-4]    ;把x的值传给eax
0040D419   mov         dword ptr [ebp-0Ch],eax  ;把x的值给内存中留一个副本
0040D41C   mov         ecx,dword ptr [ebp-0Ch]  ;把x的值在ecx中留一个副本
0040D41F   sub         ecx,1      ;减1是因为下面要和6比大小,而switch中的最大值为7
0040D422   mov         dword ptr [ebp-0Ch],ecx
0040D425   cmp         dword ptr [ebp-0Ch],6    ;如果比6大,则进行下一句
0040D429   ja          $L537+0Bh (0040d46c)     ;这个是default的第一句的行号
0040D42B   mov         edx,dword ptr [ebp-0Ch]
0040D42E   jmp         dword ptr [edx*4+40D4DAh];40D4DAh处是静态查找表的首地址
9:        case 1:
10:           y++;
0040D435   mov         eax,dword ptr [ebp-8]
0040D438   add         eax,1
0040D43B   mov         dword ptr [ebp-8],eax
11:           break;
0040D43E   jmp         $L537+14h (0040d475)    ;$L537的值为0x0040D461是case 7的第一句,$L537+14h=0x0040D475是第一个if的第一句的行号
12:       case 2:
13:           y++;
0040D440   mov         ecx,dword ptr [ebp-8]
0040D443   add         ecx,1
0040D446   mov         dword ptr [ebp-8],ecx
14:           break;
0040D449   jmp         $L537+14h (0040d475)
15:       case 3:
16:           y++;
0040D44B   mov         edx,dword ptr [ebp-8]
0040D44E   add         edx,1
0040D451   mov         dword ptr [ebp-8],edx
17:           break;
0040D454   jmp         $L537+14h (0040d475)
18:       case 6:
19:           y++;
0040D456   mov         eax,dword ptr [ebp-8]
0040D459   add         eax,1
0040D45C   mov         dword ptr [ebp-8],eax
20:           break;
0040D45F   jmp         $L537+14h (0040d475)
21:       case 7:
22:           y++;
0040D461   mov         ecx,dword ptr [ebp-8]
0040D464   add         ecx,1
0040D467   mov         dword ptr [ebp-8],ecx
23:           break;
0040D46A   jmp         $L537+14h (0040d475)
24:       default:
25:           y++;
0040D46C   mov         edx,dword ptr [ebp-8]
0040D46F   add         edx,1
0040D472   mov         dword ptr [ebp-8],edx
26:           break;
27:       }
28:
29:       if(x == 1)
0040D475   cmp         dword ptr [ebp-4],1
0040D479   jne         $L537+25h (0040d486)
30:       {
31:           y++;
0040D47B   mov         eax,dword ptr [ebp-8]
0040D47E   add         eax,1
0040D481   mov         dword ptr [ebp-8],eax
32:       }
33:       else if(x == 2)
0040D484   jmp         $L537+72h (0040d4d3)
0040D486   cmp         dword ptr [ebp-4],2
0040D48A   jne         $L537+36h (0040d497)
34:       {
35:           y++;
0040D48C   mov         ecx,dword ptr [ebp-8]
0040D48F   add         ecx,1
0040D492   mov         dword ptr [ebp-8],ecx
36:       }
37:       else if(x == 3)
0040D495   jmp         $L537+72h (0040d4d3)
0040D497   cmp         dword ptr [ebp-4],3
0040D49B   jne         $L537+47h (0040d4a8)
38:       {
39:           y++;
0040D49D   mov         edx,dword ptr [ebp-8]
0040D4A0   add         edx,1
0040D4A3   mov         dword ptr [ebp-8],edx
40:       }
41:       else if(x == 6)
0040D4A6   jmp         $L537+72h (0040d4d3)
0040D4A8   cmp         dword ptr [ebp-4],6
0040D4AC   jne         $L537+58h (0040d4b9)
42:       {
43:           y++;
0040D4AE   mov         eax,dword ptr [ebp-8]
0040D4B1   add         eax,1
0040D4B4   mov         dword ptr [ebp-8],eax
44:       }
45:       else if(x == 7)
0040D4B7   jmp         $L537+72h (0040d4d3)
0040D4B9   cmp         dword ptr [ebp-4],7
0040D4BD   jne         $L537+69h (0040d4ca)
46:       {
47:           y++;
0040D4BF   mov         ecx,dword ptr [ebp-8]
0040D4C2   add         ecx,1
0040D4C5   mov         dword ptr [ebp-8],ecx
48:       }
49:       else
0040D4C8   jmp         $L537+72h (0040d4d3)
50:       {
51:           y++;
0040D4CA   mov         edx,dword ptr [ebp-8]
0040D4CD   add         edx,1
0040D4D0   mov         dword ptr [ebp-8],edx
52:       }
53:   }
0040D4D3   pop         edi
0040D4D4   pop         esi
0040D4D5   pop         ebx
0040D4D6   mov         esp,ebp
0040D4D8   pop         ebp
0040D4D9   ret

下面是静态查找表中的内容:
0040D4DA  35 D4 40 00 40 D4 40 00 4B  5訞.@訞.K
0040D4E3  D4 40 00 6C D4 40 00 6C D4  訞.l訞.l.
0040D4EC  40 00 56 D4 40 00 61 D4 40  @.V訞.a訞
0040D4F5  00
表中存的是0~6这7个数字对应的行号,在switch中没有3,4,所以在表中这两个的值都为
0040D46C,也就是default的第一句。
从这里,我们可以看出,switch在判断分支时,没有判断所有的可能性,而是用一个静态表来解决这个问题,所以速度要比if-else快。
但是,switch对较复杂的表达式进行判断,所以当我们需要判断一些简单数值时,用switch较好。
原创粉丝点击