C 語言 `&&` 和 `||` 具有短路特性:若左側運算元已能決定結果,右側不會被求值。這不僅是優化,更是安全編程的基石。
// 除零保護:d != 0 為假時,右側不執行,避免除零崩潰
if (d != 0 && n / d > 0) { /* ... */ }
// 空指針解引用保護:p == NULL 為真時,右側不執行,避免段錯誤
if (p == NULL || *p == '\0') { /* ... */ }
C 標準未規定函數參數求值順序。大多數實現(x86 cdecl)採用從右向左壓棧,但不可依賴。
int i = 3;
printf("%d, %d\n", i, i++); // 輸出可能 4,3(右向左)或 3,3(左向右)或其他
規則:同一表達式中對同一對象「讀取」與「修改」若無序列點隔離,行為未定義。上例中 `i` 既被讀取又被修改,且無序列點,屬 UB。
關鍵概念:序列點。在序列點之前,所有副作用必須完成;在序列點之後,尚未開始。
// 多重副作用:未定義行為
i = 3;
j = (++i) + (++i) + (++i); // GCC: j=16, i=6
// 解析:編譯器可能展開為 i=4; t1=4; i=5; t2=5; i=6; t3=6; j=t1+t2+t3;
int i = 1, j = 1, k;
i = (i++) + (++i); // GCC: i=5
k = (j++) + (++j); // GCC: k=4, j=3
編譯器對中間結果的暫存方式不同。標準不保證任何特定結果。
| 場景 | 正確寫法 | 錯誤寫法 |
|---|---|---|
| 循環計數 | `for (int i = 0; i < n; i++)` | `a[i++] = i++;` |
| 交換變量 | `tmp=a; a=b; b=tmp;` | `a ^= b ^= a ^= b;` |
| 鏈表遍歷 | `while (p) { q = p->next; ... p = q; }` | `while (p = p->next)` 修改 p 同時讀取 |