位運算直接操作二進制位,是系統編程、嵌入式開發、底層優化的利器。C 語言提供六大位運算符:
| 運算符 | 名稱 | 規則 | 典型用途 |
|---|---|---|---|
& | 位與 (AND) | 同為 1 才為 1 | 掩碼提取位、清零指定位 |
| | 位或 (OR) | 有一個 1 即為 1 | 置位、合併標誌位 |
^ | 位異或 (XOR) | 相同為 0,不同為 1 | 翻轉位、無臨時變量交換、校驗和 |
~ | 位取反 (NOT) | 0↔1 逐位翻轉 | 構造掩碼、取反操作 |
<< | 左移 | 低位補 0,高位捨棄 | 快速乘 2n、構造掩碼 |
>> | 右移 | 無符號高位補 0,有符號算術移位(視實現) | 快速除 2n、提取高位 |
void inplace_swap(int *x, int *y) {
*y = *x ^ *y;
*x = *x ^ *y;
*y = *x ^ *y;
}
原理:a ^ b ^ b = a,a ^ a ^ b = b。注意:若 x == y 會導致值歸零,實際使用需加保護。
void bit_print(int a) {
int n = 16; // 假設 16 位顯示
int mask = 1 << (n - 1); // 最高位掩碼
for (int i = 1; i <= n; ++i) {
putchar((a & mask) ? '1' : '0');
a <<= 1;
if (i % 8 == 0 && i < n) putchar(' '); // 每 8 位分組
}
printf("\n");
}
邏輯運算符處理真假值(0 為假,非 0 為真),結果僅為 0 或 1:
| 運算符 | 名稱 | 真值表 |
|---|---|---|
&& | 邏輯與 | 雙真才真 |
|| | 邏輯或 | 一真即真 |
! | 邏輯非 | 真假取反 |
若第一個操作數已能決定結果,第二個操作數不再求值。
expr1 && expr2:expr1 為假 → 直接返回假,expr2 不執行。expr1 || expr2:expr1 為真 → 直接返回真,expr2 不執行。// 1. 防止空指針解引用
if (p != NULL && *p == '\0') { ... }
// 2. 避免除零錯誤
if (d != 0 && n / d > 0) { ... }
// 3. 條件執行副作用
if (init() || fallback()) { ... } // init() 成功則不調用 fallback()
int a = 32, b = 43;
printf("a++ || b-- : %d\n", a++ || b--); // 輸出 1
printf("a=%d, b=%d\n", a, b); // a=33, b=43 (b-- 未執行!)
a++ 結果為 32(真),短路導致 b-- 不執行,b 保持 43。含副作用的表達式慎用於邏輯運算!
| 維度 | 位運算 | 邏輯運算 |
|---|---|---|
| 操作對象 | 每一個二進制位 | 整個值的真假性 |
| 結果類型 | 同操作數類型 | int (0/1) |
| 短路特性 | 無 | 有 |
| 典型場景 | 硬件寄存器、加密、壓縮 | 條件判斷、流程控制 |
// 輸入 a=19(0001 0011), b=38(0010 0110)
~a = 1110 1100 (補碼表示 -20)
a & b = 0000 0010 (2)
a | b = 0011 0111 (55) // 注意原代碼打印 a|b 錯誤調用了 a&b
a ^ b = 0011 0101 (53)
swap後 a=38, b=19
#define FLAG_READ 0x01),避免魔術數字。uint32_t),避免符號位右移行為未定義。x & (x-1) 清除最低位 1)。