switch语句的定义
语法
switch(表达式) { case 常亮表达式1: 语句; break; case 常亮表达式: 语句; break; case 常亮表达式: 语句; break; ...... default: 语句; break; }
需要注意的点
- 表达式结束不能使浮点数
- case后的值不能一样
- case后的值必须是常量
break
:break
非常重要,当执行到一个分支后 如果没有break就会继续向下执行,遇到break才跳出switch语句default
语句与位置无关,但是当default写在其他条件的前面时。如果没有break;
,就会向下继续匹配
Switch语句与 if..else语句的区别:
- switch语句只能进行等值判断,而if..else可以进行区间判断
- switch语句的执行效率远远高于if..else 在分支条件比较多的情况下,这种趋势愈发明显
观察switch语句的反汇编,看看switch语句为啥效率高
为啥switch比if..else效率高
### 游戏中的switch语句
switch(x) { case 1: printf("A /n"); break; case 2: printf("B /n"); break; case 3: printf("C /n"); break; default: printf("default /n"); break; }
编译后反汇编代码
11: switch(x) 12: { 00401038 8B 45 08 mov eax,dword ptr [ebp+8] 0040103B 89 45 FC mov dword ptr [ebp-4],eax 0040103E 83 7D FC 01 cmp dword ptr [ebp-4],1 00401042 74 0E je MyPrint+32h (00401052) 00401044 83 7D FC 02 cmp dword ptr [ebp-4],2 00401048 74 17 je MyPrint+41h (00401061) 0040104A 83 7D FC 03 cmp dword ptr [ebp-4],3 0040104E 74 20 je MyPrint+50h (00401070) 00401050 EB 2D jmp MyPrint+5Fh (0040107f) 13: case 1: 14: printf("A /n"); 00401052 68 30 00 42 00 push offset string "A /n" (00420030) 00401057 E8 B4 00 00 00 call printf (00401110) 0040105C 83 C4 04 add esp,4 15: break; 0040105F EB 2B jmp MyPrint+6Ch (0040108c) 16: case 2: 17: printf("B /n"); 00401061 68 2C 00 42 00 push offset string "B /n" (0042002c) 00401066 E8 A5 00 00 00 call printf (00401110) 0040106B 83 C4 04 add esp,4 18: break; 0040106E EB 1C jmp MyPrint+6Ch (0040108c) 19: case 3: 20: printf("C /n"); 00401070 68 28 00 42 00 push offset string "C /n" (00420028) 00401075 E8 96 00 00 00 call printf (00401110) 0040107A 83 C4 04 add esp,4 21: break; 0040107D EB 0D jmp MyPrint+6Ch (0040108c) 22: default: 23: printf("default /n"); 0040107F 68 1C 00 42 00 push offset string "default /n" (0042001c) 00401084 E8 87 00 00 00 call printf (00401110) 00401089 83 C4 04 add esp,4 24: break; 25: } 26: }
### 区别
当调教比较少的时候 没啥区别 。但是当条件比较多的时候:
11: switch(x) 12: { 0040B818 8B 45 08 mov eax,dword ptr [ebp+8] 0040B81B 89 45 FC mov dword ptr [ebp-4],eax 0040B81E 8B 4D FC mov ecx,dword ptr [ebp-4] 0040B821 83 E9 01 sub ecx,1 0040B824 89 4D FC mov dword ptr [ebp-4],ecx 0040B827 83 7D FC 03 cmp dword ptr [ebp-4],3 0040B82B 77 46 ja $L539+0Fh (0040b873) 0040B82D 8B 55 FC mov edx,dword ptr [ebp-4] 0040B830 FF 24 95 91 B8 40 00 jmp dword ptr [edx*4+40B891h] 13: case 1: 14: printf("A /n"); 0040B837 68 34 0F 42 00 push offset string "A /n" (00420f34) 0040B83C E8 CF 58 FF FF call printf (00401110) 0040B841 83 C4 04 add esp,4 15: break; 0040B844 EB 3A jmp $L539+1Ch (0040b880) 16: case 2: 17: printf("B /n"); 0040B846 68 30 00 42 00 push offset string "B /n" (00420030) 0040B84B E8 C0 58 FF FF call printf (00401110) 0040B850 83 C4 04 add esp,4 18: break; 0040B853 EB 2B jmp $L539+1Ch (0040b880) 19: case 3: 20: printf("C /n"); 0040B855 68 2C 00 42 00 push offset string "C /n" (0042002c) 0040B85A E8 B1 58 FF FF call printf (00401110) 0040B85F 83 C4 04 add esp,4 21: break; 0040B862 EB 1C jmp $L539+1Ch (0040b880) 22: case 4: 23: printf("D /n"); 0040B864 68 28 00 42 00 push offset string "D /n" (00420028) 0040B869 E8 A2 58 FF FF call printf (00401110) 0040B86E 83 C4 04 add esp,4 24: break; 0040B871 EB 0D jmp $L539+1Ch (0040b880) 25: default: 26: printf("default /n"); 0040B873 68 1C 00 42 00 push offset string "default /n" (0042001c) 0040B878 E8 93 58 FF FF call printf (00401110) 0040B87D 83 C4 04 add esp,4 27: break; 28: } 29: }
我们发现 生成一张内存表。
switch通过算法,直接一步算出地址 从表中找到需要跳转的地址
大表和小表
当生成的函数跳转地址表 每个成员有4个字节的时候 我们称之为 大表
总结:
-
即没有大表也没有小表:
- case 项小于等于3项
- case最大值和最小值差值>=255
-
有大表没小表:
- case项大于3项并且大表项空隙小于等于6个
-
有大表有小表
- case项大于3项并且大表项空隙大于6个并且case最大最小差值<255
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论