<p>n > 0 && (n & (n - 1)) == 0 可判断n是否为2的幂,因2的幂二进制仅含一个1,n-1将其右侧全置1,相与得0;但需排除0(0&(-1)=0误判)和负数(溢出或未定义行为)。</p>

为什么 n & (n - 1) 能判断 2 的幂次方
因为 2 的幂次方在二进制中只有一位是 1,其余全是 0(比如 1、10、100)。而 n - 1 会把这个唯一的 1 变成 0,并把右边所有 0 变成 1。两者按位与结果必为 0。
但要注意:这个技巧只对正整数有效,0 和负数会出错。
-
n = 8→ 二进制1000,n-1 = 7→0111,n & (n-1) == 0 -
n = 6→110,n-1 = 5→101,n & (n-1) == 4(非零)
必须排除 0 和负数
0 满足 0 & (0 - 1) 为 0(因为 -1 在补码中全为 1,0 & ~0 == 0),但它不是 2 的幂;负数在标准定义下也不属于 2 的幂次方。
所以完整判断逻辑必须加前置条件:
立即学习“C++免费学习笔记(深入)”;
- 先检查
n > 0 - 再用
(n & (n - 1)) == 0
写成一行就是:return n > 0 && (n & (n - 1)) == 0;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
编译器是否优化 n & (n - 1) 这种表达式
主流编译器(如 GCC、Clang、MSVC)在开启优化(-O2 或更高)时,会将该表达式识别为“检测单比特置位”的常见模式,并可能生成一条 tzcnt 或 bsf 指令(x86),或直接用更底层的位操作替代。但行为语义不变,无需手动替换成内置函数。
除非你明确需要 __builtin_popcount(n) == 1 这类等价写法,否则坚持用 n & (n - 1) 更直观、可读性更好。
注意:__builtin_popcount 对 0 返回 0,对 1 返回 1,但它本身不检查符号,仍需配合 n > 0 使用。
边界值测试不能漏掉 1 和 INT_MIN
1 是 2⁰,必须返回 true;INT_MIN(比如 -2147483648)是负数,必须返回 false —— 但若忘记 n > 0 判断,INT_MIN - 1 会溢出(有符号整数下未定义行为)。
实操建议:
- 用
int时,测试1、2、3、0、-1、INT_MIN - 若支持
unsigned int,可避免负数问题,但仍要排除0 - 模板函数中建议用
std::is_unsigned_v<t></t>配合静态断言,或直接限定为无符号类型
真正容易被忽略的是:溢出不是“算错”,而是未定义行为 —— 它可能在调试版正常、发布版崩溃,或者看似正常但结果随机。

















