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

C 語言前綴遞減 --y vs 後綴遞減 y--:值、副作用、序列點與 printf 參數求值順序陷阱

     編輯:C 語言問答

核心差異(同 ++)

  • --y:先遞減,**表達式值為新值**。
  • y--:先取值,**表達式值為舊值**,再遞減。

獨立語句無差異

--y;  // 效果等同 y--;  只是遞減,值被丟棄
y--;

參與運算時的差異示範

int y = 5;
int a = --y + --y;  // y=3, a=6  (依序:y=4 值4 + y=3 值3 = 7? 實際取決於求值順序!)
int b = y-- + y--;  // 未定義行為!同一表達式修改 y 兩次且非為決定新值

關鍵陷阱:printf 參數求值順序**未規定**

int x = 5, y = 5;
printf("%d,%d,%d,%d", x, y, --x + --x, y-- + y--);
// 輸出可能 3,3,6,10 也可能其他,因參數右-to-左/左-to-右/亂序均合法
  • C 標準**不規定**函數參數求值順序(C++17 起規定左到右,但 C 仍未規定)。
  • 同一參數中多次修改同一物件(--x + --x)屬於**未定義行為 (UB)**,編譯器可生成任意代碼。
  • 絕對不要在同一表達式/參數列表中對同一變數進行多次副作用操作。

安全寫法

int x = 5, y = 5;
int v1 = --x; int v2 = --x; int sum1 = v1 + v2; // 明確序列
int v3 = y--; int v4 = y--; int sum2 = v3 + v4;
printf("%d,%d,%d,%d", x, y, sum1, sum2); // 確定輸出 3,3,6,10

序列點規則速記

序列點位置保證
完整表達式結尾 (;)前所有副作用完成
&&, ||, ?:, , (逗號運算子)左運算元副作用完成、再求右運算元
函數呼叫前(參數求值後)參數副作用完成、再進入函數
函數返回後函數內副作用完成、返回值可用

總結

  • --y 值為新值,y-- 值為舊值。
  • **同一表達式/參數列表中,對同一變數最多一次副作用**。
  • printf 參數順序不可靠,**先算好存變數再傳入**。
  • 開啟 -Wall -Wextra -Wsequence-point 可捕獲部分 UB。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved