forum
forum copied to clipboard
【Zig 日报】2024-04-18 Zig 中任意精度整数用途与实现
众所周知,Zig 的一大特色就是支持任意精度的整数,比如 u1,u2,u3 等,这种整数的一个典型场景就是在进行协议解析时用,比如在 protobuf 的编码方式中,一个 message 的字段,会对应一个 Tag,低三位表示字段类型,高位表示 field number,在 Zig 中就可以用下面结构表示:
const Tag = packed struct {
field_type: u3,
field_number: u5
}
packed 的结构体会保证内存紧凑,虽然 @sizeOf(u3) 会返回 1,但用在 packed 结构体中,大小就是 3 个 bit。
由于 CPU 在访问内存时,一般都会有对齐的要求,对于这种非常规的数字,在内存中的地址会是怎样的呢?可以做一个简单的实验:
const std = @import("std");
const Foo = packed struct {
a: u3,
b: u2,
};
pub fn main() !void {
const vs = [_]u3{ 1, 2, 3 };
for (&vs) |*b| {
std.debug.print("{p}-{b}\n", .{ b, b.* });
}
std.debug.print("U3 size: {d}\n", .{@sizeOf(u3)});
std.debug.print("Foo size: {d}\n", .{@sizeOf(Foo)});
const foos = [_]Foo{
.{ .a = 1, .b = 3 },
};
std.debug.print("foo as bytes: {b}\n", .{std.mem.sliceAsBytes(&foos)});
for (foos) |b| {
std.debug.print("{any}-{any}\n", .{ &b.a, &b.b });
}
}
上面会输出:
u3@104d11a2c-1
u3@104d11a2d-10
u3@104d11a2e-11
U3 size: 1
Foo size: 1
foo as bytes: { 11001 }
u3@16b196367-u2@16b196367
通过前三个输出可以知道,每个 u3 实际占用一个字节,但当用在 packed 结构中,就会变成 3 个 bit。
其中的 11001 就是字段 a b 混合后的值,且 a 是三位,b 是高两位。
社区更多关于任意精度整数的讨论:https://ziggit.dev/t/understanding-arbitrary-bit-width-integers/2028/13