x & (x + 1) 能清空低位连续的1,因其利用x+1对末尾连续1的进位效应:末尾k个1变为0,紧邻0变为1,二者按位与使这k+1位全0,高位不变;如39(100111)& 40(101000)= 32(100000)。

要清空一个整数变量**低位连续的 1**(即从最低位开始、一段连续的 1,直到遇到第一个 0 为止),最简洁高效的位运算方法是:x & (x + 1)。
为什么 x & (x + 1) 能清空低位连续的 1
关键在于理解 x + 1 对二进制末尾连续 1 的“进位效应”:
- 若 x 的二进制以 k 个连续 1 结尾(如 ...0111,k=3),则 x + 1 必然将这 k 个 1 全部变为 0,并把紧邻的那一位 0 变为 1(即 ...1000)。
- 此时 x 和 x + 1 的低 k+1 位呈现互补关系:x 是 0111,x+1 是 1000;按位与后,这 k+1 位全为 0。
- 更高位不受影响(因为进位只发生在低位),所以 x & (x + 1) 精准清空了这 k 个连续的 1,其余位保持不变。
例如:
x = 39 → 二进制 100111(末尾三个 1)
x + 1 = 40 → 二进制 101000
x & (x + 1) = 100111 & 101000 = 100000 = 32 ✅
典型应用场景
这个操作不是理论技巧,而是真实高频出现于系统级和算法工程中:
- 内存对齐计算:将地址向下对齐到最近的 2 的幂边界。例如清空低 3 位(即对齐到 8 字节),可先用 x & (x + 1) 多次迭代,或配合掩码使用。
- 快速求下一个更高对齐值的反向步骤:(x | (n-1)) + 1 是向上对齐,而 x & ~(n-1) 是向下对齐;当 n 是 2 的幂时,x & (x + 1) 可辅助构造这类掩码。
- 状态寄存器清理:硬件状态字中,某些标志位以“连续置位”方式表示忙/就绪区间,需原子清除已处理的低位段。
与其他常见操作的对比辨析
别混淆相似但目标不同的位操作:
- x & (x - 1):清除的是最低位的单个 1(常用于统计 1 的个数),不是连续多个。
- x | (x + 1):会把低位连续 1 后面那个 0 变成 1,再把后续全变 1,是“填充”而非“清空”。
- x & ~((1 :需预先知道连续长度 k,属于静态掩码法,不适用于动态长度场景。
而 x & (x + 1) 是唯一无需预知长度、仅用一次运算即可自适应清除任意长度低位连续 1 的方案。
代码实现与注意事项
在 C/C++/Rust 等支持原生位运算的语言中直接使用:
int clear_trailing_ones(int x) {
return x & (x + 1);
}注意点:
- 对 x = -1(全 1 补码),x + 1 = 0,结果为 0 —— 符合预期(清空全部低位连续 1)。
- 对 x = 0,x + 1 = 1,0 & 1 = 0 —— 无变化,也合理(无连续 1 可清)。
- 该操作对无符号类型同样成立,且更直观(避免补码解释歧义)。

















