位運算符速查表
| 運算符 | 名稱 | 規則 | 典型用途 |
| `&` | 位與 | 同為 1 則 1 | 掩碼提取、清零、判斷奇偶 |
| `|` | 位或 | 有一個 1 則 1 | 置位、合併標志位 |
| `^` | 位異或 | 相同為 0,不同為 1 | 翻轉位、無暫存變量交換、校驗和 |
| `~` | 位取反 | 0↔1 | 構造掩碼、取補碼 |
| `<<` | 左移 | 低位補 0,高位丟棄 | 快速乘 2ⁿ、構造掩碼 |
| `>>` | 右移 | 算術/邏輯右移視類型而定 | 快速除 2ⁿ、提取高位 |
核心特性與注意事項
- 僅適用於整型(`char`、`short`、`int`、`long`、及其無符號版本)
- 移位量 ≥ 位寬屬未定義行為(如 `int` 32 位時 `x << 32` UB)
- 有符號右移:標準允許算術右移(符號位擴展)或邏輯右移(補 0),視實現而定
- 負數移位:左移負數、右移負數行為涉及實現定義/未定義,避免使用
經典位運算技巧
1. 判斷奇偶:`x & 1`
if (x & 1) puts("奇數"); else puts("偶數"); // 比 x % 2 更快
2. 清零最低位的 1:`x & (x - 1)`
// 統計 1 的個數(Brian Kernighan 算法)
int count_ones(unsigned int x) {
int c = 0;
while (x) { x &= (x - 1); c++; }
return c;
}
// 判斷是否為 2 的冪次
bool is_power_of_two(unsigned int x) {
return x && !(x & (x - 1));
}
3. 獲取最低位的 1:`x & -x`(補碼特性)
int lowbit = x & -x; // 返回 2^k,k 為最低 1 的位置
4. 無暫存變量交換(教學用,實際較慢)
void swap(int *a, int *b) {
if (a != b) { // 必須檢查別名,否則同地址會歸零
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
}
5. 變量取模 2ⁿ:`x & (n - 1)`(n 為 2 的冪)
x % 8 == x & 7
x % 16 == x & 15
6. 循環移位(旋轉)
// 32 位左旋 n 位
uint32_t rotl32(uint32_t x, int n) {
n &= 31;
return (x << n) | (x >> (32 - n));
}
實戰代碼演示
#include <stdio.h>
void print_bits(unsigned short x) {
for (int i = 15; i >= 0; i--)
putchar((x & (1 << i)) ? '1' : '0');
putchar('\n');
}
int main(void) {
unsigned short a = 521, b = 123;
printf("a = "); print_bits(a); // 0000001000001001
printf("b = "); print_bits(b); // 0000000001111011
printf("a & b = "); print_bits(a & b); // 0000000000001001 (9)
printf("a | b = "); print_bits(a | b); // 0000001001111011 (603)
printf("a ^ b = "); print_bits(a ^ b); // 0000001001110010 (594)
printf("~a = "); print_bits(~a); // 1111110111110110 (65014)
// 交換演示
int x = 19, y = 38;
printf("Before: x=%d, y=%d\n", x, y);
x ^= y; y ^= x; x ^= y;
printf("After: x=%d, y=%d\n", x, y);
return 0;
}
嵌入式實戰場景
- 寄存器操作:`REG |= (1 << BIT)` 置位,`REG &= ~(1 << BIT)` 清零
- 標志位壓縮:`struct { unsigned int flag1:1; flag2:1; ...; }`
- 網絡協議:大端序構造/解析,`(buf[0] << 24) | (buf[1] << 16) | ...`
- CRC/校驗和:異或累加
- 內存對齊掩碼:`ptr & (align - 1)` 判斷對齊