按位与 & 是对两个整数的每一位执行“同为1则得1”的二进制运算,非逻辑判断;要求操作数为整型,参与运算前会整型提升,优先级低于 ==,需括号确保逻辑正确,常用于提取或清零特定位。

按位与 & 是什么,不是逻辑与 &&
很多人一看到 & 就想到“并且”,结果在 if (a & b) 里踩坑:它不判断真假关系,而是对两个整数的每一位做二进制“同为 1 则得 1”的运算。比如 5 & 3 实际算的是 0b101 & 0b011 → 0b001 = 1,和逻辑短路完全无关。
常见错误现象:if (flags & ENABLE_LOG) 写成 if (flags && ENABLE_LOG) —— 后者只要两个非零就恒真,彻底失去位掩码意义。
-
&要求操作数是整型(int、unsigned char、std::uint32_t等),不能用于浮点或指针 - 运算前会做整型提升(如
char自动转int),注意符号扩展问题:负数char c = -1;提升后可能变成全 1 的int,影响结果 - 优先级比
==和!=低,if (flags & MASK == 0)实际等价于if (flags & (MASK == 0)),必须加括号:if ((flags & MASK) == 0)
提取某一位或一组位:用 & 配合掩码
这是最常用场景——比如从寄存器值中读取第 3 位(bit 2,从 0 开始计),或检查是否启用了某个标志位。
典型用法:(value & (1 判断第 <code>n 位是否为 1;value & 0xFF 取低 8 位。
- 推荐用无符号类型定义掩码,避免符号问题:
constexpr std::uint8_t BIT_3 = 1U - 不要手写二进制字面量(如
0b1000)依赖编译器支持,C++14 才正式支持,老项目慎用 - 如果要提取连续多位(如 bit 4~6),掩码写成
0x70(即0b1110000),再右移:(value & 0x70) >> 4
清零某些位:用 & 配合取反掩码
想把变量中某些位强制设为 0,其他位保持不变,就得先构造“除了目标位全为 1”的掩码,再与原值做 &。
例如清除 status 的第 0 和第 2 位:status = status & ~(BIT_0 | BIT_2);。这里 ~ 是按位取反,| 是按位置或,组合起来才是“只清指定位置”。
- 别漏掉括号:
~BIT_0 | BIT_2是错的,~优先级高于|,实际算的是(~BIT_0) | BIT_2 - 如果掩码是编译期常量,
~会在编译时完成,无运行时开销;但若掩码来自变量,~是实打实的指令 - 清零操作是原子的(单条指令),适合多线程中配合
std::atomic使用,但需确保整数大小匹配平台原子性要求(如 x86 上int通常可原子读写)
和 std::bitset 或 std::vector<bool></bool> 混用要注意
std::bitset 重载了 &,行为符合直觉(逐位与),但 std::vector<bool></bool> 是特化容器,其 operator&= 并不存在,也不能直接拿 std::vector<bool></bool> 和整数做 &。
错误示例:std::vector<bool> v = {1,0,1}; auto r = v & 5;</bool> —— 编译失败,因为没定义该运算符。
- 需要位运算逻辑时,优先选
std::bitset<n></n>(N 必须是编译期常量)或原始整数类型 -
std::bitset的&返回新bitset,不修改原对象;&=才是就地修改 - 跨平台注意:
std::bitset::to_ulong()在位数超unsigned long容量时抛异常,大位宽建议用to_ullong()或手动分段处理
char 或 short 直接扔进位运算,又没加 U 后缀,结果可能因符号扩展完全偏离预期。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











