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.pswp.cn/pingmian/78379.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78379.shtml
英文地址,請注明出處:http://en.pswp.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…