异或交换必须严格按a=a^b、b=a^b、a=a^b顺序执行,且要求a、b为不同内存地址的整型变量;同址操作会导致全零,浮点数/指针不可用;虽不溢出但可读性差,推荐使用std::swap或a,b=b,a。

异或交换的三步必须严格按顺序执行
异或交换不是“随便异或三次就行”,而是有固定顺序:先 a = a ^ b,再 b = a ^ b,最后 a = a ^ b。中间任何一步写错(比如把第二步写成 b = b ^ a),结果就不可控——因为此时 a 已变,b ^ a 和 a ^ b 虽然数学等价,但若编译器未做重排优化,实际执行时可能因操作数求值顺序出问题(尤其在 C/C++ 中)。
常见错误现象:交换后两变量都变成 0,或其中一个值丢失。这往往是因为误用了同一变量地址(如 swap(arr[i], arr[i]))或步骤颠倒。
- 必须确保
a和b是不同内存位置的整数变量 - 不能对浮点数、指针、结构体直接用 ——
^是位运算,只定义在整型上 - Python 中对不可变整数对象有效,但本质是重新绑定变量名;C/C++ 中才真正实现寄存器级原地更新
为什么 a == b 时会得到 0
当 a 和 b 实际指向同一内存(例如 int *p = &x; swap(*p, *p)),第一步 a = a ^ b 就变成 a = x ^ x → 0;第二步 b = a ^ b 变成 b = 0 ^ x → x;但注意此时 a 和 b 是同一个位置,赋值已覆盖原始值;第三步 a = a ^ b 实为 x ^ x = 0。最终全归零。
这不是异或逻辑错了,而是前提被破坏了:异或交换依赖“两个独立值”的信息差,同址操作让信息在第一步就坍缩了。
- 调试时若发现交换后为 0,优先检查是否传入了相同地址或数组同一索引
- 加运行时断言不现实,但函数文档里必须写明:要求
&a != &b
和加减法交换比,异或唯一优势是不溢出
a = a + b; b = a - b; a = a - b 看似更直觉,但它在 int 边界附近极易触发溢出(如 a = INT_MAX, b = 1)。而异或全程只做位翻转,无进位、无符号扩展,只要类型宽度一致,就绝对安全。
但代价是可读性差,且现代编译器对 std::swap 或三行临时变量早做了寄存器优化,性能差距几乎为零。
- 嵌入式或内核代码中若真要省一个寄存器,异或仍值得考虑
- 用户层应用开发,请直接用
std::swap(a, b)(C++)或a, b = b, a(Python) - 别为了“炫技”把
a ^= b; b ^= a; a ^= b;塞进业务逻辑里——下次你或同事 debug 时会骂人
Python 里能用,但和你想的“原地”不是一回事
Python 的整数是不可变对象,a ^= b 实际是计算新整数对象并把变量名 a 指向它。所谓“原地”只是语义上没显式声明临时变量,底层仍分配新对象。如果你在修改列表元素:lst[i] ^= lst[j],那才是真正在原内存位置做位运算(前提是 lst 存的是整数)。
容易忽略的点:Python 的 ^= 复合赋值要求左右操作数类型兼容,float 会直接报 TypeError: unsupported operand type(s) for ^=: 'float' and 'float'。
- 验证方式:用
id(a)查看交换前后对象 ID 是否变化 - 若需真正内存级原地操作(如处理
bytearray),得用ctypes或 C 扩展

















