1、Switch语句与if else的关系:正向开发时,switch 几乎就是If else语句的另一种表达方式。
if(表达式 == 常量1) { //...代码 } else if(表达式 == 常量2) { //...代码 } else if(表达式 == 常量3) { //...代码 } else { //...代码 } switch(表达式) { case 常量表达式1: 语句; break; case 常量表达式2: 语句; break; case 常量表达式3: 语句; break; case 常量表达式3: 语句; break; default: 语句; break; }
switch要求:
a、case后面必须是常量表达式
b、case后常量表达式的值不能一样
c、switch后面表达式必须为整数
2、Switch中,case分支语句小于等于3时候,编译器在执行时候与if else一模一样,大于3的时候。开始生成大表结构
源码:
void fun(int x){ switch(x) { case 1: printf("%d",1); break; case 2: printf("%d",2); break; case 3: printf("%d",3); break; /*case 4: printf("%d",4); break; case 5: printf("%d",5); break; case 6: printf("%d",6); break; */ default: printf("%s","default"); break; } } int main(int argc, char* argv[]) { fun(3); return 0; }
反汇编:
00401020 push ebp 00401021 mov ebp,esp 00401023 sub esp,44h 00401026 push ebx 00401027 push esi 00401028 push edi 00401029 lea edi,[ebp-44h] 0040102C mov ecx,11h 00401031 mov eax,0CCCCCCCCh 00401036 rep stos dword ptr [edi] 00401038 mov eax,dword ptr [ebp+8] 0040103B mov dword ptr [ebp-4],eax 0040103E cmp dword ptr [ebp-4],1 00401042 je fun+32h (00401052) 00401044 cmp dword ptr [ebp-4],2 00401048 je fun+43h (00401063) 相等则跳转,分支跳转语句,和if else跳转几乎一致 0040104A cmp dword ptr [ebp-4],3 0040104E je fun+54h (00401074) 00401050 jmp fun+65h (00401085) 00401052 push 1 00401054 push offset string "%d" (0042202c) 00401059 call printf (00401180) 0040105E add esp,8 00401061 jmp fun+77h (00401097) 00401063 push 2 00401065 push offset string "%d" (0042202c) 0040106A call printf (00401180) 0040106F add esp,8 00401072 jmp fun+77h (00401097) 00401074 push 3 00401076 push offset string "%d" (0042202c) 0040107B call printf (00401180) 00401080 add esp,8 00401083 jmp fun+77h (00401097) 00401085 push offset string "default" (00422020) 0040108A push offset string "%s" (0042201c) 0040108F call printf (00401180) 00401094 add esp,8 00401097 pop edi 00401098 pop esi 00401099 pop ebx 0040109A add esp,44h 0040109D cmp ebp,esp 0040109F call __chkesp (00401200) 004010A4 mov esp,ebp 004010A6 pop ebp 004010A7 ret
分支语句大于3的
源码:
void fun(int x){ switch(x) { case 1: printf("%d",1); break; case 2: printf("%d",2); break; case 3: printf("%d",3); break; case 4: printf("%d",4); break; case 5: printf("%d",5); break; case 6: printf("%d",6); break; default: printf("%s","default"); break; } } int main(int argc, char* argv[]) { fun(3); return 0; }
反汇编:
00401020 push ebp 00401021 mov ebp,esp 00401023 sub esp,44h 00401026 push ebx 00401027 push esi 00401028 push edi 00401029 lea edi,[ebp-44h] 0040102C mov ecx,11h 00401031 mov eax,0CCCCCCCCh 00401036 rep stos dword ptr [edi] 00401038 mov eax,dword ptr [ebp+8] 0040103B mov dword ptr [ebp-4],eax 0040103E mov ecx,dword ptr [ebp-4] 传入的参数 -1 放入第一个局部变量中 3-1=2
00401041 sub ecx,1 00401044 mov dword ptr [ebp-4],ecx 00401047 cmp dword ptr [ebp-4],5 0040104B ja $L539+11h (004010bd) 跳入default 0040104D mov edx,dword ptr [ebp-4] 00401050 jmp dword ptr [edx*4+4010E0h] 查表直接跳转到分支语句,因此它的效率是最高的 $L533: 00401057 push 1 00401059 push offset string "%d" (0042202c) 0040105E call printf (00401180) 00401063 add esp,8 00401066 jmp $L539+23h (004010cf) $L535: 00401068 push 2 0040106A push offset string "%d" (0042202c) 0040106F call printf (00401180) 00401074 add esp,8 00401077 jmp $L539+23h (004010cf) $L536: 00401079 push 3 0040107B push offset string "%d" (0042202c) 00401080 call printf (00401180) 00401085 add esp,8 00401088 jmp $L539+23h (004010cf) $L537: 0040108A push 4 0040108C push offset string "%d" (0042202c) 00401091 call printf (00401180) 00401096 add esp,8 00401099 jmp $L539+23h (004010cf) $L538: 0040109B push 5 0040109D push offset string "%d" (0042202c) 004010A2 call printf (00401180) 004010A7 add esp,8 004010AA jmp $L539+23h (004010cf) $L539: 004010AC push 6 004010AE push offset string "%d" (0042202c) 004010B3 call printf (00401180) 004010B8 add esp,8 004010BB jmp $L539+23h (004010cf) 004010BD push offset string "default" (00422020) 004010C2 push offset string "%s" (0042201c) 004010C7 call printf (00401180) 004010CC add esp,8 004010CF pop edi 004010D0 pop esi 004010D1 pop ebx 004010D2 add esp,44h 004010D5 cmp ebp,esp 004010D7 call __chkesp (00401200) 004010DC mov esp,ebp 004010DE pop ebp 004010DF ret
总结:
生成大表直接查表的跳转,分支语句需要大于3,
生成的大表
3、既生成大表也生成小表的情况
源码:
void fun(int x){ switch(x) { case 1: printf("%d",1); case 8: printf("%d",8); break; case 9: printf("%d",9); break; case 10: printf("%d",10); break; default: printf("%s","default"); break; } } int main(int argc, char* argv[]) { fun(9); return 0; }
反汇编:
00401020 push ebp 00401021 mov ebp,esp 00401023 sub esp,44h 00401026 push ebx 00401027 push esi 00401028 push edi 00401029 lea edi,[ebp-44h] 0040102C mov ecx,11h 00401031 mov eax,0CCCCCCCCh 00401036 rep stos dword ptr [edi] 00401038 mov eax,dword ptr [ebp+8] 0040103B mov dword ptr [ebp-4],eax 0040103E mov ecx,dword ptr [ebp-4] 00401041 sub ecx,1 00401044 mov dword ptr [ebp-4],ecx 00401047 cmp dword ptr [ebp-4],9 0040104B ja $L537+11h (004010a1) 0040104D mov eax,dword ptr [ebp-4] 00401050 xor edx,edx 00401052 mov dl,byte ptr (004010d8)[eax] 地址 004010d8+eax处的值 00401058 jmp dword ptr [edx*4+4010C4h] 4010c4 大表的地址,下边跟着很多小表的地址 $L533: 0040105F push 1 00401061 push offset string "%d" (0042202c) 00401066 call printf (004011b0) 0040106B add esp,8 $L535: 0040106E push 8 00401070 push offset string "%d" (0042202c) 00401075 call printf (004011b0) 0040107A add esp,8 0040107D jmp $L537+23h (004010b3) $L536: 0040107F push 9 00401081 push offset string "%d" (0042202c) 00401086 call printf (004011b0) 0040108B add esp,8 0040108E jmp $L537+23h (004010b3) $L537: 00401090 push 0Ah 00401092 push offset string "%d" (0042202c) 00401097 call printf (004011b0) 0040109C add esp,8 0040109F jmp $L537+23h (004010b3) 004010A1 push offset string "default" (00422020) 004010A6 push offset string "%s" (0042201c) 004010AB call printf (004011b0) 004010B0 add esp,8 004010B3 pop edi 004010B4 pop esi 004010B5 pop ebx 004010B6 add esp,44h 004010B9 cmp ebp,esp 004010BB call __chkesp (00401230) 004010C0 mov esp,ebp 004010C2 pop ebp 004010C3 ret
总结:大表是连续的地址储存的是分支跳转的地址
中间隔开的值比较小的话,大表填充的是default的地址
中间隔开比较大的时候,会生成小表,查小表来跳转