首页 > 编程语言 >C++ 中 switch 的性能优化

C++ 中 switch 的性能优化

时间:2023-06-15 15:01:49浏览次数:44  
标签:case 编译器 C++ break switch func 优化


问题

有这样一段代码,编译器会傻傻地做多次 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) 空间复杂度。

C++ 中 switch 的性能优化_c++


那么,是不是所有场景编译器都能做优化呢?我们把 case 4、case 5 改成两个比较大的值看看。从下图可以发现,优化失效,编译器改用 compare 来定位分支。

C++ 中 switch 的性能优化_编译器_02


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

C++ 中 switch 的性能优化_编译器_03

总结

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

补充

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

我们的一些 if else 如果能转换成 switch,能让编译器生成更好的代码。因为 if else 对于编译器来说,优化起来更难一些:

C++ 中 switch 的性能优化_开发语言_04


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

C++ 中 switch 的性能优化_开发语言_05


标签:case,编译器,C++,break,switch,func,优化
From: https://blog.51cto.com/u_16162111/6492556

相关文章

  • 小议C++函数签名与模板返回类型
    题记:什么事情都要追问一个为什么,真正理解了为什么,才能活学活用。代码1下面的代码能编译通过吗?#include<stdio.h>#include<stdlib.h>classX{public:int*get(){returnnewint();}double*get(){returnnewdouble();}};intmain(){int*v1=X()......
  • C++模板
    1.名词概念模板类,模板函数,特化模板(templatespecialization)2.注意事项模板必须在头文件中实现,以下情况除外:如果只在cpp内用到的模板函数,是可以在cpp中实现的,参见oceanbase/updateserver中的response_data_函数;还有特化的模板函数,也可以在cpp中实现,参见oceanbase/updateserver中的......
  • C++类中static不计算入sizeof
    classMyParam{public:inta;staticintb;intc;staticinty;staticintz;};sizeof(MyParam)=8intMyParam::b=10;intMyParam::z=10;intmain(){MyParamp;MyParamdest;p.a=10;p.b=2;p.c=4;memcpy(&am......
  • C++构造函数复习
    #include<iostream>usingnamespacestd;classElement{public:Element(inte=12):elem(e){cout<<"element1"<<endl;}intelem;};classArrayHelper{public:ArrayHelper(){......
  • 【SQL 优化器技术系列】谓词推导
    Oracle2005年出了一个30多页的小册子,《QueryOptimizationinOracleDatabase10gRelease2》,介绍了常见的优化器技术。我是做SQL执行的,优化部分只了解皮毛,从没有系统学习过。本系列逐个学习和介绍,自我提升,也帮助他人。谓词推导(Transitivepredicategeneration)听上去高大上......
  • 【SQL 优化器技术系列】谓词下推和上拉
    Oracle2005年出了一个30多页的小册子,《QueryOptimizationinOracleDatabase10gRelease2》,介绍了常见的优化器技术。我是做SQL执行的,优化部分只了解皮毛,从没有系统学习过。本系列逐个学习和介绍,自我提升,也帮助他人。一个复杂query里可能包含多个视图和子查询(下称语句块......
  • 【SQL 优化器技术系列】 外连接消除
    Oracle2005年出了一个30多页的小册子,《QueryOptimizationinOracleDatabase10gRelease2》,介绍了常见的优化器技术。我是做SQL执行的,优化部分只了解皮毛,从没有系统学习过。本系列逐个学习和介绍,自我提升,也帮助他人。外连接消除就是将一个outerjoin转换成innerjoin。......
  • 如何寻找 C++ 程序中的大对象?
    问题背景大型应用程序中包含成千上万个C++对象,这些对象大小如何?有没有一些大对象很废?例如,在OceanBase0.4开源版本中Top10的大对象,最大的一个占58MB内存:排序大小类名158,720,304rootserver::ObRootTable2220,163,008updateserver::ObUpdateServerMain320,15......
  • C++ 文件和流
     到目前为止,我们已经使用了 iostream 标准库,它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。本教程介绍如何从文件读取流和向文件写入流。这就需要用到C++中另一个标准库 fstream,它定义了三个新的数据类型:数据类型描述ofstream该数据类......
  • C/C++商品信息管理系统[2023-06-15]
    C/C++商品信息管理系统[2023-06-15]选题4商品信息管理系统的设计与实现设计要求本课题要求同学们完成一个信息管理类的课题---《商品信息管理系统》,能够对商品信息进行有效的管理,实现商品信息查询、商品销售、商品进货、商品销售信息统计等方面的基本操作。管理内容(商品信息......