forum icon indicating copy to clipboard operation
forum copied to clipboard

【Zig 日报】2024-04-18 Zig 中任意精度整数用途与实现

Open jiacai2050 opened this issue 1 year ago • 0 comments

众所周知,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

jiacai2050 avatar Apr 18 '24 01:04 jiacai2050