1. 按位与 &

运算规则

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

特点

  • 有0出0,全1出1
  • 常用于”清零”、“提取”某些位

示例

int a = 0b1100;  // 12
int b = 0b1010;  // 10
int c = a & b;   // 0b1000 = 8
 
/*
  1100
& 1010
  ----
  1000
*/

※ 有关 a 和 b 变量中数值存储的方式以及运算的具体过程,参见数值的存储法与运算法。

常见应用

① 判断奇偶

if (n & 1) {          // 1 = 0b0000 0000 ... 0001,因此 n&1的值 = n二进制最低位
    printf("奇数\n"); // 二进制最低位为1,则n = 某正整数*2+1 => 偶数+1 => 奇数
} else {
    printf("偶数\n"); // 二进制最低位为0,则n = 某正整数*2 => 偶数
}

② 提取特定位

int num = 0b1010 1100;
int low_4bits = num & 0x0F;   // 提取低4位:0b1100      (0x0F = 0b0000 1111)
int high_4bits = num & 0xF0;  // 提取高4位:0b1010 0000 (0xF0 = 0b1111 0000)

③ 清零特定位

int num = 0b1111 1111;
int clear_low_4 = num & 0xF0;  // 清零低4位:0xF0 = 0b1111 0000

④ 判断是否为 2 的幂

bool is_power_of_2(int n) {
    return n > 0 && (n & (n - 1)) == 0;
}
// 8 (1000) & 7 (0111) = 0,是2的幂
// 6 (0110) & 5 (0101) = 0100,不是2的幂

※ 为什么可以这样写?参见快速判断n是否为2的幂。


2. 按位或 |

运算规则

0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

特点

  • 有1出1,全0出0
  • 常用于”置位”操作

示例

int a = 0b1100;  // 12
int b = 0b1010;  // 10
int c = a | b;   // 0b1110 = 14
 
/*
  1100
| 1010
  ----
  1110
*/

常见应用

① 设置特定位为 1

int num = 0b1010 0000;
int set_bit_2 = num | 0b0000 0100;  // 设置第2位为1:0b1010 0100

② 合并标志位(常用)

#define FLAG_A 0x01  // 0001
#define FLAG_B 0x02  // 0010
#define FLAG_C 0x04  // 0100
#define FLAG_D 0x08  // 1000
 
int flags = 0;
flags |= FLAG_A;  // 启用A:0001
flags |= FLAG_C;  // 启用C:0101
// 同时启用了 A 和 C

3. 按位异或 ^

运算规则

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

特点

  • 相同得 0,不同得 1
  • 常用于”翻转”、“加密”

示例

int a = 0b1100;  // 12
int b = 0b1010;  // 10
int c = a ^ b;   // 0b0110 = 6
 
/*
  1100
^ 1010
  ----
  0110
*/

常见应用

① 翻转特定位(巧妙)

int num = 0b1010 0000;
int toggle_bit_4 = num ^ 0b0001 0000;  // 翻转第4位:0b1011 0000
异或数位原数位结果
000
011
101
110

结论:异或数位为0 => 原数不变;异或数位为1 => 原数取反。

② 不借助临时变量交换两个数(巧妙)

原理:【与加密原理相同】与同一数异或两次等于没有异或。

int a = 5, b = 9;
a ^= b;  // a = 5^9
b ^= a;  // b = 9^(5^9) = 5
a ^= b;  // a = (5^9)^5 = 9
// 现在 a=9, b=5

③ 简单加密

char data = 'A';        // 0100 0001
char key = 0x55;        // 0101 0101
char encrypted = data ^ key;  // 0001 0100
char decrypted = encrypted ^ key;  // 0100 0001 = 'A'

④ 找出唯一的奇数次数数字

// 数组中只有一个数字出现奇数次,其他都是偶数次
int find_odd(int arr[], int n) {
    int result = 0;
    for (int i = 0; i < n; i++) {
        result ^= arr[i];
    }
    return result;
}
// [1,2,3,2,1] → 1^2^3^2^1 = 3

4. 按位取反 ~

运算规则

~0 = 1
~1 = 0

特点

  • 一元运算符,将所有位取反
  • 包括符号位,可能将整数翻转为负数

示例

int a = 0b0000 1100;  // 12
int b = ~a;          // 0b1111 0011 = -13 (补码表示)

常见应用

① 快速计算相反数(巧妙)

int x = 5;
int neg_x = ~x + 1;  // -5
// 计算机用补码表示负数

※ 为什么?参见快速取相反数算法的数学原理。

② 生成掩码

int mask = ~0;        // 所有位为1:0xFFFFFFFF
int low_byte_mask = ~0xFF;  // 高24位为1,低8位为0(假设为64位系统,int变量占4个字节)

5. 左移 <<

运算规则

  • 所有位向左移动,右边补 0
  • 对移出的高位部分的处理方式为未定义行为
  • 每左移 1 位,相当于乘以 2

示例

int a = 0b0000 1100;  // 12
int b = a << 1;      // 0b0001 1000 = 24
int c = a << 2;      // 0b0011 0000 = 48
int d = a << 4;      // 0b1100 0000 = 192

常见应用

① 快速乘法

int x = 5;
int result1 = x << 1;  // 10 (5×2)
int result2 = x << 3;  // 40 (5×8)
int result3 = x << 4;  // 80 (5×16)

② 创建掩码

int bit_3 = 1 << 3;   // 0b00001000 (第3位为1)
int bits_0_3 = (1 << 4) - 1;  // 0b00001111 (低4位全为1)

③ 组合标志位

#define BIT0 (1 << 0)  // 0001
#define BIT1 (1 << 1)  // 0010
#define BIT2 (1 << 2)  // 0100
#define BIT3 (1 << 3)  // 1000

6. 右移 >>

运算规则

  • 所有位向右移动,丢弃移出的低位部分
  • 左边补位取决于类型:

示例

// 正数右移(补0,逻辑右移)
int a = 0b1100 0000;  // 192
int b = a >> 1;      // 0b0110 0000 = 96
int c = a >> 2;      // 0b0011 0000 = 48
 
// 负数右移(补1,算术右移)
int d = -8;          // 0b1111 1000 (补码)
int e = d >> 1;      // 0b1111 1100 = -4
int f = d >> 2;      // 0b1111 1110 = -2

常见应用

① 快速除法(2的幂)

int x = 100;
int result1 = x >> 1;  // 50 (100÷2)
int result2 = x >> 2;  // 25 (100÷4)
int result3 = x >> 3;  // 12 (100÷8,向下取整)

② 提取高位

int num = 0b1010 1100;
int high_4 = num >> 4;  // 0b0000 1010
// 64位系统中,int类型变量占4byte=32bit,故第7位(从第0位开始)并非最高位

7. 复合赋值运算符

a &= b;   // 等价于 a = a & b
a |= b;   // 等价于 a = a | b
a ^= b;   // 等价于 a = a ^ b
a <<= n;  // 等价于 a = a << n
a >>= n;  // 等价于 a = a >> n

8. 运算符优先级

从高到低:

1. ~          // 按位取反
2. <<  >>     // 移位
3. &          // 按位与
4. ^          // 按位异或
5. |          // 按位或
6. &= ^= |= <<= >>=  // 复合赋值

注意:位运算符优先级低于算术运算符,建议使用括号明确意图。


9. 综合应用实例

① 位字段管理

// 定义一个8位状态寄存器
unsigned char status = 0;
 
// 设置第3位(从0开始)
status |= (1 << 3);
 
// 清除第3位
status &= ~(1 << 3);
 
// 切换第3位
status ^= (1 << 3);
 
// 检查第3位
if (status & (1 << 3)) {
    printf("第3位是1\n");
}

② RGB颜色处理

// 将RGB打包成32位整数
unsigned int rgb = (r << 16) | (g << 8) | b;
 
// 提取各颜色分量
int r = (rgb >> 16) & 0xFF;    // 0xFF=0b1111 1111
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;

③ 权限系统(巧妙,重要)

#define PERM_READ    (1 << 0)  // 0001 = 1
#define PERM_WRITE   (1 << 1)  // 0010 = 2
#define PERM_EXECUTE (1 << 2)  // 0100 = 4
#define PERM_DELETE  (1 << 3)  // 1000 = 8
 
int permissions = 0;
 
// 授予读写权限
permissions |= PERM_READ | PERM_WRITE;  // 0011 = 3
 
// 检查是否有读权限
if (permissions & PERM_READ) {
    printf("有读权限\n");
}
 
// 撤销写权限
permissions &= ~PERM_WRITE;  // 0001 = 1

④ 高效计算

// 计算2的n次方(n < 31)
int power_of_2 = 1 << n;
 
// 判断奇偶(odd adj.奇数的)
bool is_odd = n & 1;