
用 % 运算符判断最直接,但要注意负数
绝大多数人第一反应是 n % 2 == 0,这在非负整数下完全正确。但 C++ 中负数取模结果的符号取决于编译器实现(C++11 起规定与被除数同号),比如 -3 % 2 可能是 -1,导致 -3 % 2 == 0 为 false —— 这本身没错,但容易让人误以为“逻辑不统一”。
实操建议:
- 如果只处理非负
int(如数组索引、计数器),n % 2 == 0安全、清晰、无性能问题 - 如果可能含负数且你关心“数学意义上的奇偶”(即能否被 2 整除),应改用
abs(n) % 2 == 0,但注意abs(INT_MIN)溢出,需单独处理 - 更稳妥的写法是
n & 1 == 0:位运算对所有有符号整数都稳定,n为偶数时最低位必为 0
n & 1 是最快也最安全的位运算方案
现代 CPU 对位运算几乎零开销,& 1 直接提取二进制最低位,无需考虑符号、溢出或除法指令延迟。它不依赖数学定义,只依赖整数的补码表示 —— 而这是 C++ 标准强制要求的。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 写成
n & 1 == 1判断奇数:错!因为&优先级低于==,实际等价于n & (1 == 1)→n & 1,碰巧结果对,但逻辑混乱 - 写成
n & 0x1:等价,但没必要,1更直观 - 对
unsigned int也适用,且无任何副作用
避免用 / 2 * 2 或浮点转换这类低效写法
有人试图用 n / 2 * 2 == n 来绕过取模,或者转成 double 再用 fmod —— 这些做法既慢又危险。
原因很实在:
-
n / 2 * 2在负数截断时行为不确定(C++ 整数除法向零取整,-3 / 2是-1,-1 * 2是-2 ≠ -3,结果看似对,但逻辑断裂) - 浮点转换可能丢失精度:
INT_MAX转double后无法精确表示,fmod结果不可靠 - 编译器通常不会帮你优化掉这些冗余计算,尤其开启
-O0时
模板函数封装时,别忽略 unsigned 和 char 的隐式转换
如果写个通用判断函数,比如 template<typename t> bool is_even(T n) { return n & 1 == 0; }</typename>,看着没问题,但调用 is_even('A') 或 is_even(5U) 可能触发意外的整型提升或符号扩展。
关键细节:
-
char传入后先提升为int,不影响结果,但若原意是按字节判断,就偏离了 -
unsigned short同样提升为int,但如果值超过INT_MAX(极罕见),提升后符号位可能被误读 —— 实际中几乎不发生,但标准没保证 - 最省心的做法是限定参数类型:
bool is_even(int n)或用static_assert(std::is_integral_v<t>)</t>加约束
事情说清了就结束。真正要注意的不是“怎么写”,而是“输入范围是否可控”和“要不要为负数兜底”——这两个问题没想清楚前,选哪种写法都是临时解。









