按位运算 - C++
按位运算
- 1. 多状态/属性“打包”到一个字节里
- 读某个位
- 写某个位
- 第 loc 位设置成 val(0 或 1),其他位保持不变。
- 第 loc 位是不是 1
- 翻转某个位
- 2. 多个小量合并进一个字节或整数(节省通信)
- 3. 利用掩码管理多路开关/多通道
- 4. 快速判断奇偶性
- 5. 只保留低N位/高N位
- 6. 按位轮询查找第一个有效位
- 7. 多功能复用,动态切换
- 8. 条件组合批量操作
- 批量置位
- 批量清零
- 9. 校验/掩码设计(协议)
- 10. 轻量状态机或权限表设计
- 11. 多状态一次判断/多条件快速统计
- 12. 高级技巧:循环左移/右移,构造循环状态
- 总结
1. 多状态/属性“打包”到一个字节里
思路
用每个位表示一种状态(或属性),单字节/多字节可以表达2ⁿ种组合,比数组/结构体节省内存、传输方便。
例子:打包关节/电机/传感器状态
uint8_t status = 0;
// bit 0: 使能
// bit 1: 错误
// bit 2: 电机方向
// bit 3: 手动模式
// ... 其余位自由定义
读某个位
bool is_enabled = (status & (1<<0)) != 0; // 检查bit0
写某个位
// 置1
status |= (1<<1); // 设为错误
// 置0
status &= ~(1<<1); // 清除错误
第 loc 位设置成 val(0 或 1),其他位保持不变。
uint8_t update_bit(uint8_t original, bool val, uint8_t loc)
{uint8_t keep_bit = ~(1<<loc); // 设置掩码,除了第 loc 位都为1return (original & keep_bit) | (val<<loc); // 清掉loc位,按val补上
}
- 生成掩码
- (1<<loc) :第 loc 位为1,其余为0
- ~(1<<loc) :第 loc 位为0,其余为1(比如 loc=3,则掩码是 11110111)
- 清除原数据第 loc 位
- original & keep_bit :把第 loc 位清零,其他位不变
- 把 val 写入第 loc 位
- val<<loc :把 0/1 挪到正确的位置
- 两者相加(或|操作)
- 这样最终结果:只有 loc 位是 val,其他都和 original 相同
第 loc 位是不是 1
bool get_bit(uint8_t original, uint8_t loc)
{uint8_t bit_to_check = (1<<loc); // 构造一个第loc位为1的掩码return (original & bit_to_check) == bit_to_check; // 按位与,判断那一位是不是1
}
- 1<<loc:把 1 左移 loc 位,只保留你要检查的那一位,其余是0
- original & bit_to_check:把其他位都抹掉,只剩下感兴趣的那一位
- 比较结果是不是等于 bit_to_check,为真则原本那一位就是1,否则是0
翻转某个位
status ^= (1<<2); // 切换方向
2. 多个小量合并进一个字节或整数(节省通信)
例子:
把两个 4 位的小量合成一个 8 位字节
uint8_t high_nibble = (a & 0x0F) << 4;
uint8_t low_nibble = (b & 0x0F);
uint8_t packed = high_nibble | low_nibble;
还原
uint8_t a = (packed >> 4) & 0x0F;
uint8_t b = packed & 0x0F;
更多位宽
-
10 位 + 6 位合成 16 位
-
5 个 3 位数据合成 16 位(高效打包)
3. 利用掩码管理多路开关/多通道
比如 8 个舵机、LED 灯、传感器:
uint8_t channel_mask = 0b10101100; // 表示哪些通道开/关for (int i=0; i<8; i++) {if (channel_mask & (1<<i)) {// 开第i路} else {// 关第i路}
}
一行代码处理所有通道的状态,非常高效!
4. 快速判断奇偶性
bool is_even = ((val & 1) == 0);
bool is_odd = ((val & 1) == 1);
不用除法取模,运算极快!
5. 只保留低N位/高N位
只取低4位
uint8_t lower_4 = val & 0x0F;
只取高4位
uint8_t upper_4 = (val & 0xF0) >> 4;
6. 按位轮询查找第一个有效位
比如找到第一个出错的传感器:
uint8_t error_mask = 0b01011000;
for (int i=0; i<8; i++) {if (error_mask & (1<<i)) {// 第i个传感器出错,优先级最高break;}
}
7. 多功能复用,动态切换
用一字节高4位表示类型,低4位表示子类型/状态
uint8_t id = (type << 4) | subtype;
拆分:
uint8_t type = (id >> 4) & 0x0F;
uint8_t subtype = id & 0x0F;
8. 条件组合批量操作
批量置位
status |= (1<<1) | (1<<3) | (1<<5); // 一次性置多位
批量清零
status &= ~((1<<1) | (1<<3) | (1<<5));
9. 校验/掩码设计(协议)
数据有效位+奇偶校验+预留位混合打包,通讯协议里常见。
10. 轻量状态机或权限表设计
比如用一字节管理多个权限(读、写、执行、调试)
enum Access {ACCESS_READ = 1 << 0,ACCESS_WRITE = 1 << 1,ACCESS_EXECUTE = 1 << 2,ACCESS_DEBUG = 1 << 3,
};uint8_t user_perm = ACCESS_READ | ACCESS_EXECUTE;
if (user_perm & ACCESS_WRITE) { ... }
11. 多状态一次判断/多条件快速统计
判断有多少路为1(统计 set bit 数)
int count = 0;
uint8_t val = 0b10110101;
for (int i=0; i<8; i++) count += (val>>i)&1;
// 更快的算法也有,比如Kernighan方法
12. 高级技巧:循环左移/右移,构造循环状态
// 循环左移
uint8_t val = 0b10010011;
val = (val << 1) | (val >> 7); // 循环左移一位
总结
这些技巧的核心思想就是:
- 每一位当做一个独立的开关/状态/属性
- 批量管理,批量判断,批量修改,省空间省代码量
- 通信协议、状态机、错误检测、权限系统,全部都能用上