C 語言中「副作用」指修改對象或文件狀態的操作(賦值、自增、函數調用等),而「序列點」是執行時間線上的特殊節點:**此前所有副作用已完成,之後副作用未開始**。標準規定:兩個序列點之間,同一對象至多被修改一次。違反即導致未定義行為 (UB),表達式結果不可預測。
int x = 1, y;
y = x++ + x++; // UB!x 在兩個序列點(語句首/尾)之間被修改兩次
編譯器可能產生 2、3、4 等任意結果,甚至發射導彈 (理論上)。**切勿在單一表達式中多次修改同一對象**。
輸出 **49** 而非 56。原因:後綴 `++` 承諾「序列點前完成修改」,但**不保證何時修改**。編譯器常選「先用舊值相乘,序列點前再雙增」。
左側 `a[i]` 讀取 `i`,右側修改 `i`,**讀取未用於計算寫入值** → 違反「前值僅用於決定新值」規則 → UB。甚至 `i` 是否增 1 都不保證!
Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.
翻譯:在相鄰序列點間,對象值至多被修改一次;前值僅能用於確定要存儲的新值。
保證**短路求值**語義:左側決定結果時右側不計算,需明確左右順序。逗號運算符保證左運算副作用完成後再右運算。
理解序列點與副作用,是寫出**可移植、無 UB** C 代碼的基石。下次見到花式自增表達式,直接重構 —— 別拿未定義行為賭明天的發布!