Ziglings 笔记 97: 位运算的魔法 (XOR Swap)

能够“看见”比特

在 Ziglings 的第 97 个练习中,我们暂时放下了高层的抽象,拿起了手术刀,直接对内存中的二进制位进行操作。

位运算 (Bit Manipulation) 是程序员内功深厚的体现。虽然我们平时写业务逻辑很少用到,但在优化性能、处理硬件协议或编写加密算法时,它就是唯一的语言。

挑战:不使用第三个变量的交换

通常我们交换两个变量需要一个 temp

const temp = a;
a = b;
b = temp;

但在内存极度受限(如早期的嵌入式设备)或者为了炫技(面试中),我们可能会用到 XOR Swap 算法。题目要求我们补全这个算法。

解决方案

这个算法总是由三步组成:

const std = @import("std");
const print = std.debug.print;

pub fn main() !void {
    // 初始值
    // x = 1101 (13)
    // y = 1011 (11)
    var x: u8 = 0b1101;
    var y: u8 = 0b1011;

    // Step 1: x 变成了 "x 和 y 的差异掩码"
    // x = 1101 ^ 1011 = 0110
    x ^= y;

    // Step 2: y 利用差异掩码变成了原来的 x
    // y = 1011 ^ 0110 = 1101 (原 x)
    y ^= x;

    // Step 3: x 利用差异掩码和新的 y (原 x) 变成了原来的 y
    // x = 0110 ^ 1101 = 1011 (原 y)
    // 补全这一行:
    x ^= y;

    print("x = {b}; y = {b}\n", .{ x, y });
}

核心知识点总结

1. XOR 的本质

XOR (异或) 可以被理解为“不进位加法”。 或者更直观地理解为:两次异或同一个数,等于没操作

  • 你有一个值 A
  • 你异或上 K (Key),它变成了加密值 E
  • 你再异或一次 K,它又变回了 A。 交换算法利用的正是这个“可逆性”。

2. 现代编程建议

虽然 XOR Swap 很酷,但在现代 Zig 编程中,如果你想交换变量,请直接使用 std.mem.swap(T, &a, &b)。 或者就用临时变量 temp。 为什么?

  1. 可读性:XOR Swap 很难一眼看懂。
  2. 性能:现代编译器极其聪明。对于 temp 写法,编译器通常能直接优化成寄存器重命名或单一的 XCHG 汇编指令,这比做三次异或运算要快得多。
  3. 安全性:XOR Swap 有一个致命缺陷——如果 xy 指向同一块内存地址x ^= x 会直接把该地址清零!

3. 位运算的应用场景

除了交换,位运算更多用于:

  • 掩码 (Masking): x & 0x0F (只取低4位)。
  • 标志位 (Flags): flags |= READ_ONLY (设置标志)。
  • 紧凑存储: 使用 u1packed struct 来压缩数据。

后续预告:我们已经体验了底层的位运算。接下来的练习通常会进入更实际的系统编程领域,例如处理 Pointers to Pointers 或者更深入的 C Interop 细节。准备好继续深入了吗?