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

C 語言操作符優先級、求值順序與副作用陷阱實戰演練

     編輯:關於C語言

C 表達式中操作符優先級、結合性、副作用(++/--、賦值)交織極易產生未定義行為或邏輯錯誤。本文通過三組精心設計的測試用例,涵蓋位運算、關係/條件運算符、邏輯短路與副作用順序,幫你建立精確的心智模型。

Task 1:位運算符優先級與邏輯運算符交互

#define PRINT(expr) printf(#expr " = %d\n", expr)
int x=3, y=2, z=1;  // 0b11, 0b10, 0b01
PRINT(x | y & z);        // 3 | (2 & 1) = 3 | 0 = 3
PRINT(x | y & ~z);       // 3 | (2 & ~1) = 3 | (2 & 0xFE) = 3 | 2 = 3
PRINT(x ^ y & ~z);       // 3 ^ (2 & ~1) = 3 ^ 2 = 1
PRINT(x & y && z);       // (3 & 2) && 1 = 2 && 1 = 1

x=1; y=-1;
PRINT(!x | x);           // (!1) | 1 = 0 | 1 = 1
PRINT(~x | x);           // ~1 | 1 = -2 | 1 = -1 (全 1)
PRINT(x ^ x);            // 0
x <<= 3; PRINT(x);       // 8
y <<= 3; PRINT(y);       // -8
y >>= 3; PRINT(y);       // -1 (算術右移保持符號位)

關鍵點:& 優先於 |、^;位運算符優先於邏輯運算符;~ 為按位取反;負數右移為實現定義(通常算術右移)。

Task 2:賦值右結合、條件運算符副作用、關係運算符左結合陷阱

int x=1, y=1, z=1;
x += y += z;             // x += (y += 1) → x=3, y=2, z=1
PRINT(x < y ? y : x);    // 3<2?2:3 → 3
PRINT(x < y ? x++ : y++); // 3<2? x++ : y++ → y++=2, y=3
PRINT(x); PRINT(y);      // 3, 3
PRINT(z += x < y ? x++ : y++); // z += (3<3? x++ : y++) → z+=3=4, y=4
PRINT(y); PRINT(z);      // 4, 4

x=3; y=z=4;
PRINT((z >= y >= x) ? 1 : 0); // (4>=4)→1, 1>=3→0 → 0  【關鍵:關係運算符左結合,結果為 0/1 再參與下一比較】
PRINT(z >= y && y >= x);      // (4>=4)&&(4>=3) → 1

核心教訓:a >= b >= c **不等價於數學鏈式比較**,實為 (a>=b) >= c,中間結果為 0/1,極易寫錯。

Task 3:邏輯短路與副作用順序(序列點規則)

#define PRINT3(x,y,z) printf(#x "=%d " #y "=%d " #z "=%d\n",x,y,z)

x=y=z=1;
PRINT3(++x || ++y && ++z); // ++x=2→真,短路,y,z 不變 → 2,1,1
x=y=z=1;
PRINT3(++x && ++y || ++z); // ++x=2, ++y=2→真,短路 → 2,2,1
x=y=z=1;
PRINT3(++x && ++y && ++z); // 全真 → 2,2,2

x=y=z=-1;
PRINT3(++x && ++y || ++z); // ++x=0→假,++y=0→假,++z=0→真 → 0,-1,0
x=y=z=-1;
PRINT3(++x || ++y && ++z); // ++x=0→假,++y=0→假,++z=0→真 → 0,0,-1
x=y=z=-1;
PRINT3(++x && ++y && ++z); // ++x=0→假,短路 → 0,-1,-1

鐵律:&&、||、?:、, 為**序列點**,左運算元**完全求值含副作用**後再決定是否求右運算元。**絕不**在無序列點表達式中多次修改同一對象(如 i = i++ + ++i → UB)。

避坑清單

  1. 複雜表達式拆分為多條語句,用中間變量存儲中間結果。
  2. 開啟 -Wsequence-point -Wunsequenced(GCC/Clang)捕獲潛在 UB。
  3. 條件運算符 ?: 中僅放置無副作用純計算,副作用移至語句層面。
  4. 鏈式比較改用 (a>=b) && (b>=c) 明確邏輯。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved