C++ 中 switch 的性能优化

news2024/11/25 6:43:22

问题

有这样一段代码,编译器会傻傻地做多次 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
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/571368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件设计师 试题六零基础做题方法分解

接口要实现implements&#xff0c;父类要继承extends 做题技巧&#xff1a;如果在接口下的代码可以不写public 接口后面有个代码&#xff0c;在下面代码中一定有implements对他实现&#xff0c;接口下面是抽象方法也就是函数的实现&#xff0c;具体的实现再类中&#xff0c; 就…

Spring的Bean的生命周期

Spring的Bean的生命周期 Spring的Bean的生命周期 Spring的Bean的生命周期 Spring的Bean的生命周期包括以下阶段&#xff1a; &#xff08;1&#xff09;实例化Instantiation&#xff08;2&#xff09;填充属性Populate properties&#xff08;3&#xff09;处理Aware接口的回调…

华为OD机试真题 Java 实现【查找充电设备组合】【2023Q1 100分】

一、题目描述 某个充电站&#xff0c;可提供n个充电设备&#xff0c;每个充电设备均有对应的输出功率。任意个充电设备组合的输出功率总和&#xff0c;均构成功率集合P的1个元素。功率集合P的最优元素&#xff0c;表示最接近充电站最大输出功率p_max的元素。 二、输入描述 输…

( 链表) 203. 移除链表元素 ——【Leetcode每日一题】

❓203. 移除链表元素 难度&#xff1a;简单 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1…

探秘 | 如何分辨内网和外网?

目录 &#x1f4a1; 什么是外网IP、内网IP&#xff1f; &#x1f4a1; 对于自有路由器上网的用户&#xff0c;可以这样理解外网IP、内网IP &#x1f4a1; 几个大家经常会问的问题 什么是外网IP、内网IP&#xff1f;很多用户都有一个疑惑&#xff0c;如果不使用路由器拨号上网…

一则历史:为什么网络路径前加一个盘符还能正常工作

有一个比较知名的奇异特性&#xff1a;文件系统在解析 UNC(Universal Naming Convention) 路径时&#xff0c;会故意忽略掉最前面添加的盘符字母。 举个例子&#xff0c;假设服务器上有一个共享文件夹&#xff0c;其路径为&#xff1a;\\server\share\directory&#xff0c;如果…

【网络】HTTP

在上面的文章中&#xff0c;我们学习了网络的基础&#xff0c;和网络中一个伟大的标准 OSI 7层模型。通过上篇文章&#xff0c;我们可以知道网络模型最上层为应用层&#xff0c;那么这篇文章就让我们来一起看一下&#xff0c;我们开发过程中绕不开的一个非常著名的应用层协议&a…

FANUC机器人CC-Link总线通信相关配置的具体方法和步骤详解

FANUC机器人CC-Link总线通信相关配置的具体方法和步骤详解 1. 基本说明 2. 采用CC-Link通信的前提条件 机器人需要安装软件:CC-link Interface(Slave) A05B-*-J786 机器人需要安装硬件通信板卡:CC-Link Remote Device Station PCB A05B- * -J110 通信板卡的安装步骤:

第八章 模块

内容框架 8.1 模块介绍 引入模块 import 模块名 通过一句话&#xff0c;计算机就在指定的位置找到了模块文件&#xff0c;并准备好该文件拥有之后会用到的函数和属性。 引入模块本质上就是在一个python文件中引入另一个python文件 引入模块在文档中还可以设置别名&#xff1a;…

没有权限merge到源git仓库?一招教你如何解决。

在git上贡献项目的时候&#xff0c;一般步骤是&#xff0c;clone源项目到本地&#xff0c;切出一个新的分支&#xff0c;然后在新分支上开发&#xff0c;最后push到远程&#xff0c;然后提出mr。但是对于一些非开源的项目&#xff0c;可能会出现&#xff1a; 这就是说明没有权…

mp4是什么格式?如何录制mp4格式的视频?

案例&#xff1a;怎样录制mp4格式的视频&#xff1f; 【我发现网上大部分视频都是mp4格式&#xff0c;我也想在电脑上录制mp4格式的视频。有没有小伙伴知道录制的方法&#xff1f;】 日常生活中&#xff0c;mp4格式已经成为了我们最常用的视频格式之一。它具有高质量、高压缩…

chatgpt赋能python:Python主进程:一步步了解Python中最重要的进程

Python主进程: 一步步了解Python中最重要的进程 在Python编程中&#xff0c;进程是非常重要的一个概念。Python主进程是Python程序在启动的时候默认创建的一个进程&#xff0c;它是整个程序的核心。在使用Python进行开发的时候&#xff0c;了解Python主进程的概念和功能是非常…

gitlab搭建与认证登录

gitlab搭建与认证登录 gitlab的安装配置gitlab中Ldap认证配置 gitlab的安装配置 参考链接&#xff1a; Gitlab 仓库搭建&#xff08;详细版&#xff09; 以下4项注意点&#xff1a; gitlab安装包&#xff0c;直接访问在浏览器上下载速度很慢&#xff0c;可复制链接到迅雷中进…

淘宝店铺所有商品数据接口

淘宝店铺所有商品数据接口是淘宝提供的一种可以获取某个淘宝店铺所有商品信息的接口。通过该接口&#xff0c;可以获取到该店铺的所有商品信息&#xff0c;包括商品的标题、价格、销量、评分等。接口返回的数据格式为JSON格式&#xff0c;可以方便地处理数据。 我们可以通过调…

[论文评析]C-Mixup: Improving Generalization in Regression, NeurIPS,2022

C-Mixup: Improving Generalization in Regression 前言C-MixupReferences 前言 Mixup方法是针对分类任务的, 这篇方法相当于时提出了regression版本的Mixup, 实验证实能够大幅提升在regression task上的泛化能力. C-Mixup 是否可以把Mixup直接用于Regression task呢? 在原…

仓储服务-采购业务

1.合并采购需求 请求参数 {purchaseId: 1, //整单iditems:[1,2,3,4] //合并项集合 }(1) 合并时如果未选择合并的采购单&#xff0c;则先新建采购单然后合并到新建的采购单 新建的采购单&#xff0c;可以手动给采购单分配人员 &#xff08;2&#xff09;合并时选中了采购单…

linuxOPS基础_运维概述,及其泛概念

运维岗位定义 什么是运维&#xff1f; ​ 在技术人员&#xff08;写代码的&#xff09;之间&#xff0c;一致对运维有一个开玩笑的认知&#xff1a;运维就是修电脑的、装网线的、背锅的岗位。 ​ IT运维管理是指为了保障企业IT系统及网络的可用性、安全性、稳定性&#xff0…

学习go的操作(本人已有c的基础,请思考后再看)

建立一个文件&#xff08;我的第一个文件是hellow.go&#xff09;&#xff0c;后在终端执行一下几步&#xff1a;我用的是go build先编译成了可执行文件&#xff08;.exe&#xff09;【1.go build hellow.go 2.hellow.exe】。当然&#xff0c;你也可以用go run直接运行【…

【c语言习题】函数递归调用实现汉诺塔

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c语言系列专栏&#xff1a;c语言之路重点知识整合 &#x…

stable-diffusion安装controlnet插件

1、通过url安装controlnet插件 1&#xff09;extensions → install from URL → install 然后填入&#xff1a;https://github.com/Mikubill/sd-webui-controlnet 2&#xff09;installed → apply and restart UI 2、下载模型 下载controlnet模型&#xff08;50G左右&#…