位運算符基礎
| 運算符 | 名稱 | 規則 | 典型用途 |
& | 按位與 | 同為1才為1 | 清零特定位、取指定位 |
| | 按位或 | 有1即為1 | 置位特定位 |
^ | 按位異或 | 不同為1 | 翻轉特定位、無暫存變數交換 |
~ | 按位取反 | 0↔1 | 產生遮罩、補碼運算 |
<< | 左移 | 低位補0,高位捨棄 | 乘 2ⁿ、組合旗標 |
>> | 右移 | 算術/邏輯視實作 | 除 2ⁿ、提取高位 |
核心應用技巧速查
// 假設 int 32位,k 為位索引 (0-based)
// 1. 判斷奇偶
(x & 1) == 0 // 偶數
(x & 1) == 1 // 奇數
// 2. 取第 k 位
(x >> k) & 1
// 3. 清零第 k 位
x &= ~(1 << k)
// 4. 置 1 第 k 位
x |= (1 << k)
// 5. 翻轉第 k 位
x ^= (1 << k)
// 6. 循環左移 k 位 (32位)
x = (x << k) | (x >> (32 - k))
// 7. 循環右移 k 位
x = (x >> k) | (x << (32 - k))
// 8. 無暫存變數交換
x ^= y; y ^= x; x ^= y;
// 9. 絕對值 (無分支)
int y = x >> 31;
return (x ^ y) - y;
// 10. 平均值 (防溢位)
(x & y) + ((x ^ y) >> 1)
// 11. 判斷 2 的冪次
(x & (x - 1)) == 0 && x != 0
// 12. 取模優化 (2ⁿ)
x % (1 << n) → x & ((1 << n) - 1)
// 13. 乘法優化 (2ⁿ)
x * (1 << n) → x << n
// 14. 除法優化 (2ⁿ)
x / (1 << n) → x >> n (僅非負數安全)
補碼運算恆等式
-x = ~x + 1 = ~(x - 1)
~x = -x - 1
-(~x) = x + 1
~(-x) = x - 1
x + y = x - ~y - 1 = (x | y) + (x & y)
x - y = x + ~y + 1 = (x | ~y) - (~x & y)
x ^ y = (x | y) - (x & y)
x | y = (x & ~y) + y
x & y = (~x | y) - ~x
比較運算位元實作 (無分支)
// 有號整數
x == y: ~(x - y | y - x)
x != y: x - y | y - x
x < y: (x - y) ^ ((x ^ y) & ((x - y) ^ x))
x <= y: (x | ~y) & ((x ^ y) | ~(y - x))
// 無號整數
x < y: (~x & y) | ((~x | y) & (x - y))
x <= y: (~x | y) & ((x ^ y) | ~(y - x))
實用巨集定義
#define SET_BIT(x, y) ((x) |= (1 << ((y)-1)))
#define GET_BIT(x, y) (((x) >> ((y)-1)) & 1)
#define ROT_LEFT(x, k) ((x) << (k) | (x) >> (32 - (k)))
#define ROT_RIGHT(x, k) ((x) >> (k) | (x) << (32 - (k)))
#define IS_POW2(x) (((x) & ((x)-1)) == 0 && (x) != 0)
#define OPPOSITE(x) (~(x) + 1)
#define ABS(x) ((x) ^ ((x) >> 31)) - ((x) >> 31)
#define AVG(x, y) ((x & y) + ((x ^ y) >> 1))
完整驗證程式
#include
#include
#define SET_BIT(x, y) ((x) |= (1 << ((y)-1)))
#define GET_BIT(x, y) (((x) >> ((y)-1)) & 1)
#define ROT_RIGHT(x, k) ((x) >> (k) | (x) << (32 - (k)))
#define IS_POW2(x) (((x) & ((x)-1)) == 0 && (x) != 0)
#define OPPOSITE(x) (~(x) + 1)
int avg(int x, int y) { return (x & y) + ((x ^ y) >> 1); }
bool is_pow2(int x) { return (x & (x - 1)) == 0 && x != 0; }
void swap(int *x, int *y) { *x ^= *y; *y ^= *x; *x ^= *y; }
int main() {
int a = 0x0D; // 1101
printf("a=%d\n", a);
printf("bit2=%d\n", GET_BIT(a, 2));
SET_BIT(a, 2);
printf("set bit2: a=%d, bit2=%d\n", a, GET_BIT(a, 2));
int c = ROT_RIGHT(a, 33%32);
printf("rot right 1: c=%d, bit5=%d\n", c, GET_BIT(c, 5));
printf("avg(8,692)=%d\n", avg(8, 692));
for (int i = 0; i < 1000; i++)
if (IS_POW2(i)) printf("%-5d", i);
printf("\n");
int x = 10, y = 90;
swap(&x, &y);
printf("swap: x=%d, y=%d\n", x, y);
printf("OPPOSITE(-705)=%d\n", OPPOSITE(-705));
return 0;
}
面試高頻考點
- 無暫存變數交換:理解 XOR 特性,注意
x=y 時歸零問題
- 判斷 2 的冪次:
x & (x-1) 清除最低位 1,結果為 0 則只有一個 1
- 平均值防溢位:
(x&y) + ((x^y)>>1) 分解為共同位 + 差異位一半
- 絕對值無分支:利用算術右移複製符號位
- 位運算優化除模乘:僅適用 2 的冪次,有號數右移需謹慎
避坑指南
- 移位超寬度:
1 << 32 未定義行為,需 1ULL << 32
- 有號數右移:算術/邏輯移位視實作定義,可移植代碼避免依賴
- 優化前提:編譯器 -O2 通常自動優化乘除模,手動優化需測試驗證
- 可讀性權衡:關鍵路徑加註解,非熱點優先清晰代碼