(环境: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较好。