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

MTK 筆試心得(一):C++ 運算子求值順序與序列點陷阱

     編輯:關於C語言

前言:輕敵的代價

今年投入求職大軍,抱著累積經驗心態參加 MTK 筆試。自詡熟悉 C++ 進階特性(模板、STL、Boost),卻在基礎題上栽了大跟頭。這篇記錄第一道讓我「體無完膚」的題目——看似簡單的輸出順序問題,實則暗藏 C++ 求值順序與序列點的深坑。

陷阱題目

int a = 10, b = 6;
cout << a + b << " " << a++ << " " << b++;

直覺答案:16 10 6(先算 a+b=16,再印 a++=10, b++=6)。
實際輸出(GCC 4.5):18 10 6

深度剖析:模擬類別追蹤執行流

為釐清真相,設計模擬 int 行為的類別 X,重載運算子並輸出追蹤:

X a(10), b(6);
cout << "sum:" << a + b << " a:" << a++ << " b:" << b++ << endl;

GCC 4.5 執行輸出:

construct 10
construct 6
operator ++(post) 6   // b++ 先執行
copy construct 6      // 產生臨時物件
operator ++(post) 10  // a++ 再執行
copy construct 10     // 產生臨時物件
operator +            // 最後才執行 a+b
construct 18          // 此時 a=11, b=7, 結果 18
sum:18 a:10 b:6
desconstruct 18
desconstruct 10
desconstruct 6
desconstruct 7        // a 變 11
desconstruct 11       // b 變 7

關鍵發現:參數求值順序為「從右至左」

cout << A << B << C 解析為 operator<<(operator<<(operator<<(cout, A), B), C)。
C++ 標準(C++17 前)未規定函式參數求值順序,編譯器可自由選擇。GCC 採用從右至左壓棧:

  1. 先算最右邊 b++ → 產生臨時值 6,b 變 7
  2. 再算 a++ → 產生臨時值 10,a 變 11
  3. 最後算 a+b → 此時 a=11, b=7 → 結果 18

輸出時依串流順序吐出:18 10 6。

跨編譯器差異與標準演進

  • GCC 4.5:18 10 6(右至左)
  • VS2010 Debug:16 10 6(左至右)
  • VS2010 Release:18 10 6(優化後右至左)
  • C++17 起:強制規定「從左至右」求值,此表達式行為確定為 16 10 6。

總結與警惕

  1. 切勿在單一表達式中多次修改同一物件(如 a++ + a++),行為未定義。
  2. 避免依賴參數求值順序的邏輯,拆分為多行語句確保可移植性。
  3. 基礎比進階更重要:對「序列點」、「求值順序」、「臨時物件生命週期」的模糊理解,是導致失誤的根源。

這道題讓我明白:C++ 的水深在基礎細節,而非花俏特性。筆試題往往正是考驗這些「基本功」。

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