C++ 中 switch 的性能优化

问题

有这样一段代码,编译器会傻傻地做多次 compare 来找到对应分支吗?

#include <stdio.h>
#include <stdlib.h>
int func(int i)
{
    return (long)(&i) + i + rand();
}

int test(int flag)
{
	int i = 0;
	switch (flag) {
	case 0:
		i += func(i);
		break;
	case 1:
		i += func(i+11);
		break;
	case 2:
		i += func(i+111);
		break;
	case 3:
		i += func(i+112);
		break;
	case 4:
		i += func(i+1123);
		break;
	case 5:
		i += func(i+131);
		break;
	default:
		i += func(i+311);
		break;
	}
	return i;
}

江湖传言,编译器会自动对 switch 做自动优化。使用在线汇编工具 Compiler Explorer 可以很方便地做实验,观察 C 语言对应的汇编代码,我们来看看。

实验

实验效果很好!如下图所示,flag 有 6 个取值,编译器能自动计算出一个 jump table,然后根据 flag 值直接做跳转,把 O(n) 的计算复杂度转化成 O(1),非常高效。代价嘛,则是增加了 jump table 带来的 O(n) 空间复杂度。
在这里插入图片描述
那么,是不是所有场景编译器都能做优化呢?我们把 case 4、case 5 改成两个比较大的值看看。从下图可以发现,优化失效,编译器改用 compare 来定位分支。

我们可以猜测,编译器最擅长对取值连续的 switch case 做优化,比如 flag = 0…5。如果有少许间隔,但是间隔并不大,估计编译器还是可以做好优化。下面试试把 case 4 改成 case 10,可以发现,优化的确依然生效。
在这里插入图片描述

总结

当 switch 的取值 “比较连续” 的情况下,编译器会使用 jump table 技术来优化 switch 的执行。当连续性很差的时候,优化效果不佳。

补充

  1. 如何写出编译器友好的代码

我们的一些 if else 如果能转换成 switch,能让编译器生成更好的代码。因为 if else 对于编译器来说,优化起来更难一些:
在这里插入图片描述
2. 离散值的 switch 优化

对于离散值,还是有办法做优化的。核心想法是构建 hash 表,通过查表的方式来做跳转。在存在大量离散值的场景里,hash 查表的方法比 if else 决策树的方法性能更好。详细情况可以参考这篇文章:https://programming.sirrida.de/hashsuper.pdf
在这里插入图片描述


我写的小程序广告:

如果你朋友或亲戚家有小朋友在读一年级,这个口算天天练打印免费网站送给你:https://reactshare.cn/kousuan/
在这里插入图片描述在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值