最直接安全的偶数判断是 n % 2 == 0,它语义清晰、跨平台一致;n & 1 虽快但负数行为未被标准保证,仅适用于非负整数或 unsigned 类型。

用 % 取模是最直接、最安全的判断方式
绝大多数情况下,直接写 n % 2 == 0 就够了。它语义清晰、编译器优化成熟、对正数/负数/零都行为一致。c++ 标准规定:当 a 为负时,a % b 的符号与被除数 a 相同,但 n % 2 的结果只会是 0、1 或 -1 —— 所以必须用 == 0 判断偶数,不能用 == 1 反推奇数。
-
n = -4→-4 % 2 == 0为true(偶数) -
n = -3→-3 % 2 == -1,所以-3 % 2 == 0是false(奇数) - 别写
n % 2当布尔值用,因为-1在 if 中也是 true,会误判
位运算 & 1 快但有前提条件
用 n & 1 确实快(单条 CPU 指令),但它只在整数以二进制补码形式存储且为非负数时“看起来可靠”。问题在于:C++ 标准不保证负数的位表示,而实际中几乎所有平台用补码,-3 & 1 确实等于 1,-4 & 1 等于 0 —— 但这属于实现细节,不是标准行为。
- 仅对
unsigned类型或已知非负的int安全使用n & 1 - 对
int n = -1,n & 1在补码下是1,但标准不保证;换成static_cast<unsigned>(n) & 1</unsigned>也不行——负数转 unsigned 是定义良好的(模 2^N),但结果和原意脱钩(比如-1变成大正数,再 & 1 还是 1,碰巧对,但逻辑断裂) - 现代编译器对
n % 2通常自动优化成位运算,没必要手写& 1
模板函数封装时要注意类型和 const 建议
如果想写个通用函数,别直接用 int,也别忽略 const 和引用。尤其注意 std::size_t、long long 等类型可能不支持 % 2?其实都支持,但取模对无符号类型是明确定义的。
- 推荐签名:
template<typename t> constexpr bool is_even(T n) { return n % 2 == 0; }</typename> - 加
constexpr让编译期常量也能用 - 避免传值 + 修改参数,不加
const容易误导调用者以为函数会改它 - 别为性能对
char或short特化成& 1—— 提升微乎其微,还引入风险
遇到 abs(n) % 2 这类写法要警惕
有人想“统一处理负数”,写 abs(n) % 2,这反而引入新问题:INT_MIN 调用 abs 是未定义行为(因为 INT_MAX )。Clang/GCC 在 -fsanitize=undefined 下会报错。
立即学习“C++免费学习笔记(深入)”;
- 绝对不要对
int直接用abs再取模 - 若真需要无符号视角,用
static_cast<unsigned>(n) % 2</unsigned>(此时INT_MIN会转成大正数,但% 2结果仍正确) - 更稳妥:坚持用
n % 2 == 0,它本身就能正确处理所有有符号整数边界值
真正容易被忽略的是:很多人记住了“位运算快”,却忘了它绑定硬件表示,而取模语义稳定、编译器懂优化、代码可读性强——除非你在裸金属环境手写驱动且 profiling 确认这是瓶颈,否则就老实用 % 2。