异或交换仅适用于不同地址的整型变量,自交换会导致结果为0;判断奇偶推荐n & 1而非n % 2;n & (n - 1)可清最低位1,用于判2的幂或统计比特数;有符号数右移行为依赖实现,应转unsigned确保逻辑右移。

用 ^ 异或交换两个整数,但别在同一个变量上操作
异或交换(a ^= b; b ^= a; a ^= b;)确实不需临时变量,但它只安全用于两个**不同地址的变量**。如果写成 swap(&a, &a) 或对数组元素如 arr[i] ^= arr[j]; ... 且 i == j,结果直接变 0——因为 x ^ x == 0,后续所有操作都崩了。
实际建议:
- 日常优先用
std::swap(a, b),编译器会自动优化为高效指令,还避免自交换风险 - 真要手写异或交换,加个地址判等:
if (&a != &b) { a ^= b; b ^= a; a ^= b; } - 注意:该技巧仅适用于整型(
int、long等),浮点数、指针、类对象不能直接异或
n & 1 判断奇偶比 n % 2 == 1 更快也更可靠
取模运算在负数时行为易出错:-3 % 2 在 C++ 中结果是 -1(不是 1),所以 n % 2 == 1 会漏判负奇数。而 n & 1 直接看最低位,对所有有符号整数都成立——-3 的补码末位仍是 1,-3 & 1 == 1。
使用要点:
- 只对整型有效;
char、short会被提升,没问题;bool也可用,但没必要 - 编译器通常能把
n & 1优化成单条test指令,比除法快一个数量级 - 别写成
n & 0x1——虽然等价,但1更直观,且无符号扩展歧义
用 n & (n - 1) 快速清零最低位的 1,常用于统计比特数或判断 2 的幂
这个操作把整数 n 最右边的 1 变成 0,其余位不变。例如 12 & 11 → 0b1100 & 0b1011 = 0b1000。它比循环移位快得多,且能避开分支预测失败。
典型用途:
- 判断是否为 2 的幂:
n > 0 && (n & (n - 1)) == 0(注意排除 0) - 计算二进制中 1 的个数(Brian Kernighan 算法):
while (n) { n &= n - 1; count++; } - 陷阱:对
n == 0,n - 1是全 1(如0xffffffff),0 & 0xffffffff == 0,不会崩溃但逻辑需单独处理
右移符号位填充依赖编译器实现,跨平台务必用 unsigned 类型
C++ 标准规定:对有符号数右移(>>),高位填 0 还是填符号位由实现定义。GCC/Clang 在 int 上做算术右移(填符号位),但若你期望逻辑右移(填 0),必须先转成 unsigned。
比如想把 -8 >> 2 当作无符号操作得到 0x3ffffffe(即 1073741822),就得写:(static_cast。
关键提醒:
- 别依赖
int右移结果做位模式解析,尤其在网络字节序、图像像素处理等场景 -
std::bitset和std::uint32_t等固定宽度无符号类型是最安全的选择 - 即使目标平台一致,开启不同优化等级(如
-O2vs-O0)也可能影响未定义行为的暴露时机
位运算本身很轻量,但语义隐含强、边界多。最常被忽略的是类型符号性与平台差异——写一次看似能跑,换编译器或升级标准库就翻车。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










