C 語言早期設計時,為了兼容既有代碼與硬件特性,部分運算符優先級的安排並不符合直覺,甚至被丹尼斯·里奇事後承認為「錯誤」。若不加括號,極易寫出語義與預期完全相反的代碼。
| # | 表達式 | 直覺理解 | 實際解析 | 結果差異 |
|---|---|---|---|---|
| 1 | *p.f | (*p).f 取指向結構體指針的成員 | *(p.f) 先取 p 的成員 f 再解引用 | 結構體指針 vs 結構體成員指針 |
| 2 | int *ap[] | int (*ap)[] 指向數組的指針 | int *(ap[]) 指針數組 | 完全不同的類型聲明 |
| 3 | int *fp() | int (*fp)() 函數指針 | int *(fp()) 返回指針的函數 | 聲明語義顛倒 |
| 4 | val & mask != 0 | (val & mask) != 0 | val & (mask != 0) 先做關係運算 | 位運算變邏輯判斷 |
| 5 | c = getchar() != EOF | (c = getchar()) != EOF | c = (getchar() != EOF) 先比較再賦值 0/1 | 讀取字符 vs 讀取布爾值 |
| 6 | msb << 4 + lsb | (msb << 4) + lsb | msb << (4 + lsb) 先加法再移位 | 移位位數錯誤 |
| 7 | i = 1, 2 | i = (1, 2) 逗號運算符整體賦值 | (i = 1), 2 先賦值 1,逗號後表達式被丟棄 | i 為 1 而非 2 |
-Wparentheses(GCC/Clang)可提示潛在優先級問題。「好的代碼不僅能讓編譯器理解,更能讓六個月後的自己秒懂。」—— 加括號,是對未來維護者最大的善意。