核心差異(同 ++)
--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。