c/c++里的if和switch的区别
# 0x01 总叙大家都知道, c/c++在需要分支判断时, 有两个方法, 也就是if和switch
通常, 授课教师会告诉我们, switch使用了优化算法, 比if更高效(至少我学的时候老师是这样说的), 并且很多大型项目中多分支判断也用switch
举个例, cpython里的ceval.c(也就是执行python字节码的地方), 就有个大switch结构
(已将case内部折叠)
那么, 这两个方式到底有什么区别
# 0x02 测试
社么东西都要自己试试才好, 这里写两段c++代码, 如下
```cpp
// 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;
}
}
```
```cpp
// 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:
```sh
cl if.cpp
cl switch.cpp
```
linux:
```sh
g++ if.cpp -o if
g++ switch.cpp -o switch
```
使用该python脚本记录时间
```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 +=
# 使用switch
for i in range(5):
time_list_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
另外, 大家遇到不懂得问题可以自己动手去尝试, 自己经过尝试得到的结果比任何教程, 博客等等都有用 开了O2之后,你能想到的常数优化基本都有了,真当编译器的开发人员没普通人聪明?
O0这东西存在的意义估计就是让某些专业的学生探究下编译原理吧( emmm编译难道会不一样么?
记得之前有看到switch编译后变成通过eax跳转,
就只有一行 jmp (类似的语句)
就实现了分支跳转,
而if就只能一个个的判断 其实从if和switch 两个单词的含义来看,if就没有switch快。:lol switch L7那里没看明白,他应该是比较值后直接跳转对应的label吧,但是.long是什么东西???
塞北的雪 发表于 2021-8-16 19:51
switch L7那里没看明白,他应该是比较值后直接跳转对应的label吧,但是.long是什么东西???
long应该是数据类型
一般c/c++中int的类型好像在底层就是long类型 先收藏了,仔细理解 一直只是听说switch快,也不知道为什么,感谢lz的深入分析~ 看来switch会比较好用,待我细细品一下