首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ return 語句底層機制:結構體回傳值的堆疊幀與臨時物件真相

     編輯:關於C++

當函數回傳 struct/class 物件時,編譯器在背後做了什麼?本文通過反組譯碼逐行解析,揭示 回傳值優化(RVO/NRVO)之前的經典實作:呼叫端預留空間、傳遞隱藏指標、被呼叫端構造臨時物件、呼叫端再拷貝/移動的完整流程。

實驗程式碼

struct Big { char buf[100]; int i; long d; } B, B2;
Big bigfun(Big b) { b.i = 100; return b; }
int main() { B2 = bigfun(B); }

關鍵堆疊幀佈局差異

一般函數回傳結構體的函數
局部變數局部變數
EBPEBP
EIP (回傳地址)EIP
參數回傳值臨時物件地址 (隱藏參數)
參數

因寄存器太小無法裝下大型結構體,呼叫端在堆疊預留空間,將其首地址作為隱藏第一參數傳給被呼叫函數(EBP+8 位置)。

完整執行流程(x86 cdecl)

  1. main:sub esp, 118h 預留空間 → 低址放 bigfun 回傳臨時物件,高址放 B2.operator= 參數。
  2. 呼叫 bigfun:將 B 複製到參數區(rep movs)→ lea eax, [ebp-0D8h] 取臨時物件地址 → push eax 傳隱藏參數 → call bigfun。
  3. bigfun 內部:修改參數 b.i=100 → rep movs 將 b 複製到隱藏參數指向的臨時物件 → mov eax, [ebp+8] 將臨時物件地址回傳於 EAX。
  4. 返回 main:add esp, 70h 清理參數 → rep movs 臨時物件 → B2.operator= 參數 → 再 rep movs 到 B2 實際位置。

核心結論

  1. 結構體回傳值在堆疊上,不在堆上。臨時物件佔用呼叫端堆疊幀空間。
  2. 隱藏參數傳遞地址是編譯器約定俗成的 ABI(Application Binary Interface)。
  3. 涉及兩次拷貝:被呼叫端 → 臨時物件 → 呼叫端目標物件。優化編譯器會施行 RVO/NRVO 直接在目標位置構造,省去拷貝。
  4. 堆疊幀增大:sub esp, 118h 顯示 main 預留了兩個 Big 大小的空間。

現代 C++ 建議

  • 優先回傳 std::optional<Big> 或值型別,依賴 RVO/NRVO(C++17 強制保證)與移動語義。
  • 避免回傳大型結構體的指標/引用指向區域物件(懸空引用)。
  • 若效能極度敏感,考慮傳出參數 void bigfun(Big& out, const Big& in) 明確控制記憶體佈局。

透過反組譯碼看清 return 的真面目,能讓你在優化熱點路徑、排查物件生命週期 Bug 時,擁有「看穿編譯器」的 X 光眼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved