運算符與表達式是C語言程序進行計算與邏輯判斷的基石。本文系統梳理C語言所有運算符分類、優先級結合規則、隱式類型轉換規則及常見陷阱。
| 類別 | 運算符 | 目數 | 說明 |
|---|---|---|---|
| 算術 | + - * / % ++ -- | 雙目/單目 | 基本數學運算,%僅適用整數 |
| 賦值 | = += -= *= /= %= <<= >>= &= ^= |= | 雙目 | 簡單與復合賦值,右結合 |
| 關系 | < > <= >= == != | 雙目 | 返回int(1/0) |
| 邏輯 | && || ! | 雙目/單目 | 短路求值,!優先級最高 |
| 位運算 | & | ^ ~ << >> | 雙目/單目 | 操作二進制位 |
| 指針/成員 | * & -> . | 單目/雙目 | 間接訪問、地址、結構成員 |
| 條件 | ? : | 三目 | 唯一三目運算符,右結合 |
| 其他 | sizeof () , [ ] | - | 類型大小、類型轉換、逗號、下標、調用 |
1. 後綴:() [] -> . ++ --
2. 單目:++ -- + - ! ~ * & (type) sizeof ← 右結合
3. 算術:* / % ← 左結合
4. 算術:+ - ← 左結合
5. 移位:<< >> ← 左結合
6. 關系:< <= > >= ← 左結合
7. 相等:== != ← 左結合
8. 位與:& ← 左結合
9. 位異或:^ ← 左結合
10. 位或:| ← 左結合
11. 邏輯與:&& ← 左結合
12. 邏輯或:|| ← 左結合
13. 條件:? : ← 右結合
14. 賦值:= += -= ... ← 右結合
15. 逗號:, ← 左結合
口訣:單目>算術>移位>關系>相等>位&>位^>位|>邏輯&>邏輯|>條件>賦值>逗號
int a = 5, b;
b = ++a; // a=6, b=6 先增後用
b = a++; // a=6, b=5 先用後增
複雜表達式中混用前後綴屬於未定義行為(C標準未規定求值順序),如a = i++ + ++i,嚴禁編寫。
7 / 3 == 2,-7 / 3在C99前實現定義,C99規定向零截斷(結果-2)a % b符號與被除數a相同(C99規定)規則:運算前將操作數轉換為「更高」類型,保證精度不丟失:
char/short/bool/enum → int(或unsigned int)
long double > double > float > unsigned long long > long long >
unsigned long > long > unsigned int > int
陷阱:unsigned int + int → unsigned int,負數變大正數:
int a = -1;
unsigned int b = 1;
printf("%d\n", a + b); // 輸出 0 (無符號運算: UINT_MAX + 1 = 0)
if (p != NULL && p->value > 0) // p為NULL時不訪問p->value,安全
if (x > 0 || func()) // x>0為真時不調用func()
利用短路特性可簡化條件判斷、避免空指針解引用、優化性能。
int max = (a > b) ? a : b;
// 等價於
int max;
if (a > b) max = a; else max = b;
(cond ? a : b) = value;if-elsesizeof(int)需括號,sizeof x變量可不加括號sizeof(arr)得整個數組大小(僅數組定義作用域內),退化為指針時得指針大小sizeof("abc") == 4(含結束符\0)C標準未規定函數參數、運算符操作數的求值順序(除&&、||、?:、,有序點)。
int i = 5;
printf("%d %d %d\n", i++, i++, i++); // 未定義行為!輸出不可預期
func(i++, i++); // 參數求值順序未定義
鐵律:同一表達式中不得對同一變量既修改又讀取(除非用序列點分隔)。
fabs(a-b) < EPS,避免==if-else-Wall -Wextra -Wsequence-point)捕獲求值順序問題精通運算符優先級、類型轉換規則與求值順序,是編寫正確、可移植、無未定義行為C代碼的前提。