0x01 总叙
大家都知道, c/c++在需要分支判断时, 有两个方法, 也就是if和switch
通常, 授课教师会告诉我们, switch使用了优化算法, 比if更高效(至少我学的时候老师是这样说的), 并且很多大型项目中多分支判断也用switch
举个例, cpython里的ceval.c(也就是执行python字节码的地方), 就有个大switch结构
(已将case内部折叠)
那么, 这两个方式到底有什么区别
0x02 测试
社么东西都要自己试试才好, 这里写两段c++代码, 如下
// if.cpp
# include <random>
int main()
{
std::uniform_int_distribution<int> d(0, 5);
std::random_device rd;
int num = d(rd);
if(num == 0)
{
return 0;
}
else if(num == 1)
{
return 1;
}
else if(num == 2)
{
return 2;
}
else if(num == 3)
{
return 3;
}
else if(num == 4)
{
return 4;
}
else if(num == 5)
{
return 5;
}
}
// switch.cpp
# include <random>
int main()
{
std::uniform_int_distribution<int> d(0, 5);
std::random_device rd;
int num = d(rd);
switch(num)
{
case 0:
{
return 0;
break;
}
case 1:
{
return 1;
break;
}
case 2:
{
return 2;
break;
}
case 3:
{
return 3;
break;
}
case 4:
{
return 4;
break;
}
case 5:
{
return 5;
break;
}
}
}
这两段代码是否有区别? 试试才知道
给大家实验机器的配置
windows机器: Windows11, Intel Core i3-4170, msvc:19.29.30040, gcc:version 6.3.0 (MinGW.org GCC-6.3.0-1)
linux机器: Ubuntu21.04, arm64, respiberry 4 mode B, gcc:version 10.3.0 (Ubuntu 10.3.0-1ubuntu1~20.10)
我们使用以下命令编译
windows:
cl if.cpp
cl switch.cpp
linux:
g++ if.cpp -o if
g++ switch.cpp -o switch
使用该python脚本记录时间
import time
import os
def get_time(command):
t1 = time.time()
os.system(command)
t2 = time.time()
return t2 - t1
time_list_if = list()
time_list_switch = list()
# 使用if
for i in range(5):
time_list_if += [get_time('./if')]
# 使用switch
for i in range(5):
time_list_switch += [get_time('./switch')]
print('使用if判断的耗时')
print(time_list_if)
print('使用switch判断的耗时')
print(time_list_switch)
测试结果
Windows:
linux:
虽然相差不是很大, 但明显, switch胜过if
这里只有5个分支,但是如果分支足够多, 那差别就会扩大
那么, 为什么会发生这种情况呢
0x03 分析二进制
仅在windows平台测试
使用以下方法编译代码到汇编
g++ -S if.cpp
g++ -S switch.cpp
将得到的两个.s文件进行diff
找到关键区域(两个文件因为地址和变量问题, 有很多无用的差异)
左:使用if,右:使用switch
可以看到, 使用switch之前还有一些操作, 但是每次判断少了一个cmpl, jne操作, 因此, 分支越多, switch和if的速度差就越来越大
这就是switch优化的关键点
0x04 其他
本教程所涉及的代码请到这里下载
下载:https://tes286.lanzoui.com/iMFC7spxeej 密码:0x11E
另外, 大家遇到不懂得问题可以自己动手去尝试, 自己经过尝试得到的结果比任何教程, 博客等等都有用