Ziglings 笔记 64: 编译器的秘密武器 (Builtins)
能够直通 CPU 的函数
在 Ziglings 的第 64 个练习中,我们掀开了 Zig 语言的引擎盖,通过 Builtins (内置函数) 直接与编译器和 CPU 对话。
普通的函数是定义在库里的,而内置函数(以 @ 开头)是直接“长”在语言里的。它们能做一些普通 Zig 代码做不到的事情,比如检查算术运算是否丢失了进位,或者让 CPU 执行特定的指令。
挑战:溢出与反转
任务包含两部分:
- 溢出数学:计算 $13 + 5$ 的真实结果(不考虑 4 bit 限制)。
- 位操作:使用内置函数将
11110000的位序反转。
解决方案
这是完整的实现代码:
const print = @import("std").debug.print;
pub fn main() void {
// === 任务 1: 溢出加法 ===
// u4 范围是 0-15
const a: u4 = 0b1101; // 13
const b: u4 = 0b0101; // 5
// @addWithOverflow 返回一个元组: { 结果, 溢出标志 }
const my_result = @addWithOverflow(a, b);
// 打印结果: 0010 (true)
// 因为 13+5=18,二进制 10010。截断后是 0010 (2),溢出位是 1。
print("{b:0>4} + {b:0>4} = {b:0>4} ({s})", .{
a, b, my_result[0], if (my_result[1] == 1) "true" else "false"
});
// 我们的任务:计算无溢出的真实结果 (u8)
// 13 + 5 = 18 -> 二进制 00010010
const expected_result: u8 = 0b00010010;
print(". Without overflow: {b:0>8}. ", .{expected_result});
// === 任务 2: 位反转 ===
print("Furthermore, ", .{});
const input: u8 = 0b11110000;
// 使用 @bitReverse 内置函数
// 它会将二进制位像照镜子一样翻转
const tupni: u8 = @bitReverse(input);
// 输入: 11110000
// 输出: 00001111
print("{b:0>8} backwards is {b:0>8}.\n", .{ input, tupni });
}
核心知识点总结
1. @addWithOverflow
在实现大整数库(比如 RSA 加密或者区块链地址生成)时,我们需要手动处理加法产生的“进位”。Zig 暴露了这个 CPU 标志位,让我们能像汇编程序员一样精准控制数学运算,同时保持了高级语言的安全性。
2. @bitReverse
这看起来像是个简单的算法题,但在现代 CPU 上,这通常对应一条专门的硬件指令(如 ARM 的 RBIT)。使用内置函数而不是手写循环移位,可以让编译器生成最优化的机器码。
3. 内置函数生态
Zig 有超过 100 个内置函数,涵盖了:
- 数学运算:
@sqrt,@sin,@popCount(统计 1 的个数) - 类型反射:
@TypeOf,@typeInfo(这是 Zig 泛型和元编程的基础) - 内存操作:
@memcpy,@memset - 编译器控制:
@compileLog,@compileError
后续预告:我们已经见识了 Zig 的强大特性。接下来的练习将深入探讨 格式化打印 (Formatting)。除了简单的 {},Zig 还支持控制对齐、精度、填充字符等,让你能像排版工一样控制输出。