c++中的enum变量 和 constexpr说明符


author: hjjdebug
date: 2025年 04月 23日 星期三 13:40:21 CST
description: c++中的enum变量 和 constexpr说明符


文章目录

    • 1.Q:enum 类型变量可以有++,--操作吗?
      • 1.1补充: c/c++中enum的另一个细微差别.
    • 2.Q: constexpr 修饰的函数,要求传入的参数必需是常量吗?
    • 3. Q constexpr 编译期求值真正的意思是什么?
      • 3.1 debug 版本, constexpr 修饰无效
      • 3.2 release 版本, constexpr 函数被优化掉了
    • 4. constexpr 中碰到了一个左值引用绑定问题
    • 5 x86-64 linux系统上函数调用传参约定

本来应该分2篇博客写的,放一起吧,也有相关性,都是c++的.

1.Q:enum 类型变量可以有++,–操作吗?

A: c支持,c++不支持.
c++中的enum 类型变量和c中的enum变量基本含义相同,但又略有区别.
试验代码:

$ cat main.c
#include <stdio.h>
typedef enum _ABC { E0,E1,E2}ABC;
int main() 
{ABC a=E0;a++;return 0;
}

c语言是支持enum类型变量++或–这种操作的,因为它天然认为enum类型就是整形
将main.c改名为main.cpp文件,则编译不通过
给出的编译错误为:

error: no ‘operator++(int)’ declared for postfix ‘++’ [-fpermissive]

没有后++的操作运算符说明, operator++(int), 不允许的操作.
就是说c++编译器认为enum 类型是一种新的类型,并不是整型,虽然它的内部实现是把它当整形来实现的.
那如何解除这种限制呢?
如下:多加一行代码, 重载 ABC operator++(int)类型的函数. 就可以对ABC 型变量执行后++操作

$cat main.cpp
#include <stdio.h>
typedef enum _ABC { E0,E1,E2}ABC;
constexpr ABC operator++(ABC d,int) {return ABC((int)d+1);}
int main() 
{ABC a=E0;a++;return 0;
}

1.1补充: c/c++中enum的另一个细微差别.

c++中可以不用typedef 重定义类型,而直接使用enum 就可以了.如下:
enum ABC {E0,E1,E2}, 其它代码不动.
而c语言不行,
如果去掉typedef 重定义,你需要在声明变量时加上enum声明,如下:
enum ABC a=E0
否则会有编译错误,如下:

error: unknown type name ‘ABC’; use ‘enum’ keyword to refer to the type
| ABC a=E0;
| ^~~

2.Q: constexpr 修饰的函数,要求传入的参数必需是常量吗?

答: 不是
这个constexpr修饰的函数,网上说是可以编译期求值,要求传入常量值.
我看说法不完全正确,这里我传入a就是内存变量,不是常量
我还可以写如下代码:
for(int i=0;i<2;i++)
{
a++; // 这个a 是不断变化的.
printf(“a is %d\n”, (int)a);
}

3. Q constexpr 编译期求值真正的意思是什么?

A: constexpr函数并不会进入执行文件中,执行文件中没有这个函数.
正确的理解constexpr的编译期求值, 是它在运行时不求值,
就是说它已经做到了运行时, 不进入你定义的constexpr函数,
例如对该例,它的a++就直接变成了整数的a++
并不是说一定要传入常量值.

3.1 debug 版本, constexpr 修饰无效

这只是我的一种猜测,后面我会证明,
如果编译成debug版调试程序,它总是会跟入函数的, 这不是constexpr 的初衷
对debug版本,加不加constexpr 效果是一样的.

3.2 release 版本, constexpr 函数被优化掉了

那么对release 版是否真的把constexpr函数给优化掉了呢?那要反汇编代码了.
开干吧! 源代码如下:

#include <stdio.h>
typedef enum _ABC { E0,E1,E2}ABC;
constexpr ABC& operator++(ABC& d,int) {return d=ABC((int)d+1);}
int main()
{ABC a=E0;for(int i=0;i<5;i++){a++;}return 0;
}

release 版反编译代码
我惊讶的发现, 我的main函数被它优化成空函数了
如下:
0000000000001040 :
1040: f3 0f 1e fa endbr64
1044: 31 c0 xor %eax,%eax
1046: c3 retq
1047: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)

什么for循环, enum 变量,统统都是空.
哇! 这么利害,把代码全优化掉了,它认为我这些代码都是没用的东西.
是的,如果把main也当成一个一般的子函数看,它除了占用点cpu资源,对外界就没有什么影响.

我们加上printf 代码,让代码变得有用起来. 不能让它全优化了.

#include <stdio.h>
typedef enum _ABC { E0,E1,E2}ABC;
constexpr ABC& operator++(ABC& d,int) {return d=ABC((int)d+1);}
int main()
{ABC a=E0;for(int i=0;i<5;i++){a++;printf("a is %d\n",(int)a);}return 0;
}

release 版反编译代码

0000000000001060 <main>:1060:	f3 0f 1e fa          	endbr64 1064:	55                   	push   %rbp  //rbp 如栈,框架1065:	48 8d 2d 98 0f 00 00 	lea    0xf98(%rip),%rbp # 2004 <_IO_stdin_used+0x4>106c:	53                   	push   %rbx  //rbx 入栈,它会做为a变量106d:	bb 01 00 00 00       	mov    $0x1,%ebx //ebx 就是a变量,初始值给了1,因为它知道第一次打印值是1,利害!1072:	48 83 ec 08          	sub    $0x8,%rsp //调整堆栈,为局部变量准备空间1076:	89 da                	mov    %ebx,%edx // a变量送给edx, printf 的第二个参数1078:	48 89 ee             	mov    %rbp,%rsi // rsi, printf 的第一个参数,字符串地址107b:	bf 01 00 00 00       	mov    $0x1,%edi // rdi=1,向stdout输出,因为它调用的是__printf_chk1080:	31 c0                	xor    %eax,%eax // 表示传递的浮点数个数是0个1082:	e8 c9 ff ff ff       	callq  1050 <__printf_chk@plt>1087:	83 c3 01             	add    $0x1,%ebx        // ebx 为a变量//它算出了a变量和i变量的对应关系,所以优化掉i变量,让a变量与6比,果然很智能!108a:	83 fb 06             	cmp    $0x6,%ebx      108d:	75 e7                	jne    1076 <main+0x16> //循环到1076108f:	48 83 c4 08          	add    $0x8,%rsp   //局部空间栈恢复1093:	31 c0                	xor    %eax,%eax  //返回值1095:	5b                   	pop    %rbx   //恢复rbx1096:	5d                   	pop    %rbp //恢复rbp1097:	c3                   	retq   //函数返回 1098:	0f 1f 84 00 00 00 00 	nopl   0x0(%rax,%rax,1)109f:	00 

完美验证了我的设想!constexpr 函数优化后不会出现在运行期,但它也不会要求参数必需是常量,变量也行,只要能被它替代就行.

总结一下: constexpr 函数是一种可以被优化掉的函数,就是说它不会生成对应的函数代码,而是会把返回值嵌入到你调用的代码中. 返回值可能是一个常数或常量,也可以是一个变量的简单运算.就是一个变量加个偏移,乘一个数除一个数等.一般constexpr函数不会太复杂.这里先给你一个美好的心里预期!

4. constexpr 中碰到了一个左值引用绑定问题

代码:
constexpr ABC& operator++(ABC& d,int) {return ABC((int)d+1);}
error: cannot bind non-const lvalue reference of type ‘ABC&’ {aka ‘_ABC&’} to an rvalue of type ‘ABC’ {aka ‘_ABC’}
错误是说: 不能够让非-const 的左值ABC& 类型与右值 ABC类型相绑定.
就是说要返回引用,而不要返回值

修改方法.
返回一个值的引用. 一个变量的别名叫引用,引用在函数间传递的是地址,该函数实际的意义就是修改自身.
所以函数内把值再变成引用.如下:添加d=内容,把值送给引用.
constexpr ABC& operator++(ABC& d,int) {return d=ABC((int)d+1);}

5 x86-64 linux系统上函数调用传参约定

采用System V AMD64 调用约定.
前六个整型参数(包括指针)通过寄存器传递
顺序RDI、RSI、RDX、RCX R8 R9 ,超过6个多余的用堆栈传,从右向左顺序压入堆栈.
例: test(0,1,2,3,4,5,6) 7个参数
31 ff xor %edi,%edi
be 01 00 00 00 mov $0x1,%esi
ba 02 00 00 00 mov $0x2,%edx
b9 03 00 00 00 mov $0x3,%ecx
41 b8 04 00 00 00 mov $0x4,%r8d
41 b9 05 00 00 00 mov $0x5,%r9d
6a 06 pushq $0x6
//test 函数c++中变成了_Z4Testiiiiiii,名称带参数类型,_Z是gcc的函数标志,4是名称长度,7个i是7个整形参数
e8 04 01 00 00 callq 1190 <_Z4Testiiiiiii>

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

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

相关文章

postman工具

postman工具 进入postman官网 www.postman.com/downloads/ https://www.postman.com/downloads/ https://www.postman.com/postman/published-postman-templates/documentation/ae2ja6x/postman-echo?ctxdocumentation Postman Echo is a service you can use to test your …

Spring和Spring Boot集成MyBatis的完整对比示例,包含从项目创建到测试的全流程代码

以下是Spring和Spring Boot集成MyBatis的完整对比示例&#xff0c;包含从项目创建到测试的全流程代码&#xff1a; 一、Spring集成MyBatis示例 1. 项目结构 spring-mybatis-demo/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com.example/…

【数据可视化-24】巧克力销售数据的多维度可视化分析

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个…

c语言-分支结构

以下是我初学C语言的笔记记录&#xff0c;欢迎留言补充 一&#xff0c;分支结构分为几个 两个&#xff0c;一个是if语句&#xff0c;一个是Switch语句 二&#xff0c;if语句 &#xff08;1&#xff09;结构体 int main() {if()//判断条件{//表达式}else if()//判断条件{//表达式…

数据库MySQL学习——day4(更多查询操作与更新数据)

文章目录 1、聚合函数&#xff08;Aggregate Functions&#xff09;2、分组查询&#xff08;GROUP BY&#xff09;3、更新数据&#xff08;UPDATE&#xff09;4、删除数据&#xff08;DELETE&#xff09;5、进阶练习示例6、 今日小结 1、聚合函数&#xff08;Aggregate Functio…

Spark-SQL 项目

一、项目概述 &#xff08;一&#xff09;实验目标 统计有效数据条数&#xff1a;筛选出uid、phone、addr三个字段均无空值的记录并计数。提取用户数量最多的前 20 个地址&#xff1a;按地址分组统计用户数&#xff0c;按降序排序后取前 20 名。 &#xff08;二&#xff09;…

Redis的ZSet对象底层原理——跳表

我们来聊聊「跳表&#xff08;Skip List&#xff09;」&#xff0c;这是一个既经典又优雅的数据结构&#xff0c;尤其在 Redis 中非常重要&#xff0c;比如 ZSet&#xff08;有序集合&#xff09;底层就用到了跳表。 &#x1f31f; 跳表&#xff08;Skip List&#xff09;简介 …

2025深圳中兴通讯安卓开发社招面经

2月27号 中兴通讯一面 30多分钟 自我介绍 聊项目 我的优缺点&#xff0c;跟同事相比&#xff0c;有什么突出的地方 Handler机制&#xff0c;如何判断是哪个消息比较耗时 设计模式&#xff1a;模板模式 线程的状态 线程的开启方式 线程池原理 活动的启动模式 Service和Activity…

【Castle-X机器人】二、智能导览模块安装与调试

持续更新。。。。。。。。。。。。。。。 【Castle-X机器人】智能导览模块安装与调试 二、智能导览模块安装与调试2.1 智能导览模块安装2.2 智能导览模块调试2.2.1 红外测温传感器测试2.2.2 2D摄像头测试 二、智能导览模块安装与调试 2.1 智能导览模块安装 使用相应工具将智能…

深入理解二叉树遍历:递归与栈的双重视角

二叉树的遍历前序遍历中序遍历后续遍历总结 二叉树的遍历 虽然用递归的方法遍历二叉树实现起来更简单&#xff0c;但是要想深入理解二叉树的遍历&#xff0c;我们还必须要掌握用栈遍历二叉树&#xff0c;递归其实就是利用了系统栈去遍历。特此记录一下如何用双重视角去看待二叉…

Qt Creator中自定义应用程序的可执行文件图标

要在Qt Creator中为你的应用程序设置自定义可执行文件图标&#xff0c;你需要按照以下步骤操作&#xff1a; Windows平台设置方法 准备图标文件&#xff1a; 创建一个.ico格式的图标文件&#xff08;推荐使用256x256像素&#xff0c;包含多种尺寸&#xff09; 可以使用在线工…

Windows11系统中GIT下载

Windows11系统中GIT下载 0、GIT背景介绍0.0 GIT概述0.1 GIT诞生背景0.2 Linus Torvalds 的设计目标0.3 Git 的诞生&#xff08;2005 年&#xff09;0.4 Git 的后续发展0.5 为什么 Git 能成功&#xff1f; 1、资源下载地址1.1 官网资源1.2 站内资源 2、安装指导3、验证是否下载完…

react的fiber 用法

在 React 里&#xff0c;Fiber 是 React 16.x 及后续版本采用的协调算法&#xff0c;它把渲染工作分割成多个小任务&#xff0c;让 React 可以在渲染过程中暂停、恢复和复用任务&#xff0c;以此提升渲染性能与响应能力。在实际开发中&#xff0c;你无需直接操作 Fiber 节点&am…

FPGA前瞻篇-数字电路基础-逻辑门电路设计

模拟信号&#xff1a; 一条随时间连续变化、平滑波动的曲线&#xff0c;比如正弦波。 数字信号&#xff1a; 一条只有高低两个状态&#xff08;0和1&#xff09;&#xff0c;跳变清晰的方波曲线。 在 IC 或 FPGA 的逻辑设计中&#xff0c;我们通常只能处理数字信号&#xff0…

RabbitMQ 基础概念(队列、交换机、路由键、绑定键、信道、连接、虚拟主机、多租户)介绍

本文是博主在梳理 RabbitMQ 知识的过程中&#xff0c;将所遇到和可能会遇到的基础知识记录下来&#xff0c;用作梳理 RabbitMQ 的整体架构和功能的线索文章&#xff0c;通过查找对应的知识能够快速的了解对应的知识而解决相应的问题。 文章目录 一、RabbitMQ 是什么&#xff1f…

机器学习第一篇 线性回归

数据集&#xff1a;公开的World Happiness Report | Kaggle中的happiness dataset2017. 目标&#xff1a;基于GDP值预测幸福指数。&#xff08;单特征预测&#xff09; 代码&#xff1a; 文件一&#xff1a;prepare_for_traning.py """用于科学计算的一个库…

Java面试高频问题(29-30)

二十九、全链路压测&#xff1a;数据隔离与流量 关键技术点 1. 流量染色&#xff1a;通过Header注入X-Test-TraceId标识压测流量 2. 影子库表&#xff1a;通过ShardingSphere实现数据隔离 3. 熔断降级&#xff1a;压测流量触发异常时自动切换回生产数据源 数据隔离方案对比 …

Python常用的第三方模块之数据分析【pdfplumber库、Numpy库、Pandas库、Matplotlib库】

【pdfplumber库】从PDF文件中读取内容 import pdfplumber #打开PDF文件 with pdfplumber.open(DeepSeek从入门到精通(20250204).pdf) as pdf:for i in pdf.pages: #遍历页print(i.extract_text()) #extract_text()方法提取内容print(f----------------第{i.page_number}页结束…

长短板理论——AI与思维模型【83】

一、定义 长短板理论思维模型&#xff0c;也被称为木桶原理&#xff0c;是指一只木桶能盛多少水&#xff0c;并不取决于最长的那块木板&#xff0c;而是取决于最短的那块木板。该理论将木桶视为一个整体系统&#xff0c;各个木板代表着系统的不同组成部分或要素&#xff0c;强…

2025蓝桥省赛c++B组第二场题解

前言 这场的题目非常的简单啊&#xff0c;至于为什么有第二场&#xff0c;因为当时河北正在刮大风被迫停止了QwQ&#xff0c;个人感觉是历年来最简单的一场&#xff0c;如果有什么不足之处&#xff0c;还望补充。 试题 A: 密密摆放 【问题描述】 小蓝有一个大箱子&#xff0…