1.14. switch()/case/default
1.14.1. case数量较少
x86
未优化MSVC
case数量较少时,相当于数个if/else语句结合。光看汇编代码很难判断源代码是什么。
优化后的MSVC
一些优化很有趣:把a的值放在EAX中,用它减去0,用来检查a是否为0。如果ZF设置了(减法结果为0),则JE触发。接下来会分别减1、减2,即分别与1,2比较。
另一点是,调用printf()不是用CALL,而是用JMP。字符串指针放在a变量(某个内存地址),这段代码只是手动设置栈内容然后跳转。实际上是为了速度而优化。
OllyDbg
可以识别case语句。
ARM:优化Keil(ARM模式)
也是按if实现的。出现了比较多的ADRcc指令,在特定条件下加载字符串地址到R0,下一条Bxx跳转到某个位置,进行函数调用。
ARM:优化Keil(Thumb模式)
没有后缀形式,所以与x86差不多。
ARM64:未优化GCC
用w0保存输入而不是x0,因为是int类型。
用ADRP/ADD将字符串指针参数传给puts()。
ARM64:优化的GCC
用CBZ代替了复杂的指令,如果w0是0就跳转。直接跳转到puts()。
MIPS
jr $t9 跳转到puts()
LW指令后常有nop,因为load delay slot。
结论:
少量case的switch()与if/else基本没有区别。
1.14.2. 大量cases
如果case较多,则用大量JE/JNE指令是不合适的。
下面给出了一个5个case的例子。
x86
非优化的MSVC
如果a大于4,直接跳到$LN1@f(错误信息)。
如果a小于等于4,把a乘以4,再与LN11@f地址相