【C】位运算
C 语言位运算(Bitwise Operations)
位运算直接对整数的二进制位(bit)进行操作,常用于底层开发、硬件编程、数据压缩、加密算法等场景。C 语言提供了 6 种位运算符:
1. 基本位运算符
运算符 | 名称 | 描述 | 示例(假设 A = 60 , B = 13 ) |
---|---|---|---|
& | 按位与 | 两位均为 1 时结果为 1 | A & B = 12 (0011 1100 & 0000 1101 = 0000 1100 ) |
| | 按位或 | 任意一位为 1 时结果为 1 | `A |
^ | 按位异或 | 两位不同时结果为 1 | A ^ B = 49 (0011 1100 ^ 0000 1101 = 0011 0001 ) |
~ | 按位取反 | 所有位取反(0→1, 1→0) | ~A = -61 (~0011 1100 = 1100 0011 ,补码表示) |
<< | 左移 | 左移指定位数,低位补 0 | A << 2 = 240 (0011 1100 → 1111 0000 ) |
>> | 右移 | 右移指定位数,高位补符号位(算术右移)或 0(逻辑右移,取决于编译器) | A >> 2 = 15 (0011 1100 → 0000 1111 ) |
2. 常见用途
(1) 掩码操作(Masking)
- 检查某位是否为 1:
if (value & (1 << n)) { // 检查第 n 位(从 0 开始)// 第 n 位是 1 }
- 设置某位为 1:
value |= (1 << n); // 第 n 位置 1
- 清除某位为 0:
value &= ~(1 << n); // 第 n 位清 0
- 切换某位(0↔1):
value ^= (1 << n); // 第 n 位取反
(2) 快速乘除 2 的幂
- 左移代替乘法:
int x = 5; int y = x << 3; // y = x * 2³ = 40
- 右移代替除法:
int x = 20; int y = x >> 2; // y = x / 2² = 5
注意:右移负数的结果依赖编译器实现(算术/逻辑右移)。
(3) 交换变量(不使用临时变量)
a ^= b; // a = a ^ b
b ^= a; // b = b ^ (a ^ b) = a
a ^= b; // a = (a ^ b) ^ a = b
(4) 判断奇偶性
if (x & 1) { // 等价于 x % 2 != 0// 奇数
}
(5) 取绝对值(32 位整数)
int abs(int x) {int mask = x >> 31; // 正数为 0,负数为 -1(全 1)return (x ^ mask) - mask; // 负数取反加 1
}
3. 注意事项
-
符号位问题:
- 右移 (
>>
) 有符号数时,高位补符号位(算术右移)。 - 无符号数右移时,高位补 0(逻辑右移)。
- 右移 (
-
位移超出位数:
- 如果位移位数超过类型的宽度(如
int
左移 32 位),行为未定义(UB)。
- 如果位移位数超过类型的宽度(如
-
运算符优先级:
- 位运算符优先级低于算术运算符,建议用括号明确逻辑:
if (x & 0xFF == 0) // 错误!等价于 x & (0xFF == 0) if ((x & 0xFF) == 0) // 正确
- 位运算符优先级低于算术运算符,建议用括号明确逻辑:
-
可读性:
- 复杂的位操作应添加注释,或使用宏/函数封装:
#define BIT(n) (1 << n) #define IS_SET(x, n) ((x) & BIT(n))
- 复杂的位操作应添加注释,或使用宏/函数封装:
4. 实战示例
示例 1:提取 RGB 颜色分量
uint32_t color = 0xFF3366; // RGB(0xFF, 0x33, 0x66)
uint8_t r = (color >> 16) & 0xFF; // R = 0xFF
uint8_t g = (color >> 8) & 0xFF; // G = 0x33
uint8_t b = color & 0xFF; // B = 0x66
示例 2:IP 地址转换
uint32_t ip = (192 << 24) | (168 << 16) | (1 << 8) | 10; // 192.168.1.10
示例 3:位图(Bitmap)
uint8_t bitmap[16]; // 128 位位图
// 设置第 n 位
void set_bit(int n) {bitmap[n / 8] |= (1 << (n % 8));
}
// 清除第 n 位
void clear_bit(int n) {bitmap[n / 8] &= ~(1 << (n % 8));
}
5. 扩展:位域(Bit Fields)
C 语言支持在结构体中定义位域,直接控制成员的位数:
struct {unsigned int is_active : 1; // 1 位unsigned int mode : 3; // 3 位unsigned int padding : 4; // 4 位填充
} flags;
注意:位域的具体内存布局依赖编译器实现,跨平台时需谨慎。
掌握位运算可以显著提升代码在底层和高性能场景的效率,但需注意可读性和平台兼容性。