TES286 发表于 2021-8-16 19:41

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

另外, 大家遇到不懂得问题可以自己动手去尝试, 自己经过尝试得到的结果比任何教程, 博客等等都有用

无名氏wyw 发表于 2021-8-16 23:04

开了O2之后,你能想到的常数优化基本都有了,真当编译器的开发人员没普通人聪明?

O0这东西存在的意义估计就是让某些专业的学生探究下编译原理吧(

涛之雨 发表于 2021-8-16 21:28

emmm编译难道会不一样么?
记得之前有看到switch编译后变成通过eax跳转,
就只有一行 jmp (类似的语句)
就实现了分支跳转,
而if就只能一个个的判断

alanyelan 发表于 2021-8-16 22:23

其实从if和switch 两个单词的含义来看,if就没有switch快。:lol

塞北的雪 发表于 2021-8-16 19:51

switch L7那里没看明白,他应该是比较值后直接跳转对应的label吧,但是.long是什么东西???

TES286 发表于 2021-8-16 20:15

塞北的雪 发表于 2021-8-16 19:51
switch L7那里没看明白,他应该是比较值后直接跳转对应的label吧,但是.long是什么东西???

long应该是数据类型

一般c/c++中int的类型好像在底层就是long类型

tlf 发表于 2021-8-16 20:30

hswei 发表于 2021-8-16 20:45

先收藏了,仔细理解

三滑稽甲苯 发表于 2021-8-16 21:01

一直只是听说switch快,也不知道为什么,感谢lz的深入分析~

拜拜系 发表于 2021-8-16 22:58

看来switch会比较好用,待我细细品一下
页: [1] 2 3 4 5 6
查看完整版本: c/c++里的if和switch的区别