首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言運算符完全指南:優先級、結合性與經典陷阱

     編輯:關於C語言

前言

運算符是 C 語言構建表達式的基石。熟練掌握運算符的優先級、結合性、副作用及常見陷阱,能寫出正確、高效、可維護的代碼。本文系統梳理 C 語言所有運算符類別,結合經典面試題與實戰案例,助你攻克運算符難點。

一、運算符分類總覽

類別運算符示例說明
算術運算符+ - * / %基本數學運算,% 僅用於整數
關係運算符== != > < >= <=返回 1(真)或 0(假)
邏輯運算符&& || !短路求值特性
位運算符& | ^ ~ << >>操作二進制位,嵌入式開發常用
賦值運算符= += -= *= /= %=右結合性,賦值表達式有值
自增/自減++ --前置/後置區別大,副作用陷阱多
條件運算符?:唯一三目運算符,右結合
逗號運算符,最低優先級,求值結果為最後表達式
指針/成員* & -> .地址、解引用、結構體成員訪問
sizeofsizeof(type)編譯時計算類型/表達式佔用字節數

二、優先級與結合性速查表(由高到低)

1.  () [] -> .          // 函數調用、數組下標、結構體成員(左結合)
2.  ! ~ ++ -- + - * & sizeof (type)  // 單目運算符(右結合)
3.  * / %               // 乘除模(左結合)
4.  + -                 // 加減(左結合)
5.  << >>               // 移位(左結合)
6.  < <= > >=           // 關係(左結合)
7.  == !=               // 相等性(左結合)
8.  &                   // 按位與(左結合)
9.  ^                   // 按位異或(左結合)
10. |                   // 按位或(左結合)
11. &&                  // 邏輯與(左結合,短路)
12. ||                  // 邏輯或(左結合,短路)
13. ?:                  // 條件運算符(右結合)
14. = += -= *= /= %=    // 賦值(右結合)
15. ,                   // 逗號(左結合)

三、經典陷阱與最佳實踐

1. 自增自減的副作用與序列點

錯誤示例:

int i = 1;
int a = i++ + ++i; // 未定義行為!修改 i 兩次無序列點

正確理解:

  • 前置 ++i:先增後用,值為增後值
  • 後置 i++:先用後增,值為增前值
  • 同一表達式中對同一變量多次修改,或修改後又讀取(非為了計算新值),屬於未定義行為(UB)

2. 邏輯運算符的短路求值

int a = 0, b = 1;
if (a && (b = 2)) { } // b 不會被賦值為 2,因為 a 為 0 直接短路
if (a || (b = 2)) { } // b 會被賦值為 2,因為 a 為 0 需評估右側

利用短路特性可安全檢查指針:if (p && p->next)

3. 整數除法與取模的符號規則

C99 規定:a / b 向零截斷,a % b 滿足 (a/b)*b + a%b == a。

-5 / 2  == -2   // 向零截斷
-5 % 2  == -1   // 符號與被除數相同
5 % -2  == 1

4. 移位運算符的未定義行為

  • 移位位數 < 0 或 ≥ 位寬:UB
  • 左移負數:UB
  • 右移負數:實現定義(通常算術右移,符號位擴展)

5. 條件運算符的類型推導

int a = 1;
double b = 2.0;
auto c = a ? a : b; // c 類型為 double,遵循 usual arithmetic conversions

6. 逗號運算符 vs 函數參數分隔

func(a, b, c);     // 參數分隔,非逗號運算符,求值順序不定
int x = (a, b, c); // 逗號運算符,順序求值,x = c

四、實戰練習題解析

題目 1:複雜賦值表達式

int i = 1, j = 2, k = 3;
i = j = k = 4; // 右結合:k=4 → j=4 → i=4,整個表達式值為 4

題目 2:前置後置混合

int i = 5, j;
j = ++i + i++ + --i; // UB!同一序列點多次修改 i

題目 3:宏陷阱

#define SQUARE(x) x * x
int y = SQUARE(3 + 2); // 展開為 3 + 2 * 3 + 2 = 11,非 25
// 正確寫法:#define SQUARE(x) ((x) * (x))

五、總結建議

  1. 括號優先:不確定優先級時加括號,提升可讀性
  2. 避免副作用疊加:單表達式中不對同一變量多次修改
  3. 善用短路特性:指針檢查、條件執行
  4. 理解整數提升與常規算術轉換:混合類型運算時自動轉換規則
  5. 警惕宏副作用:參數多次求值、優先級問題

運算符看似基礎,實則暗藏玄機。唯有透徹理解其語義模型,方能在代碼中遊刃有餘,規避隱蔽 Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved