Packed vs extern structs

Recently I’ve been trying to generate data for R8G8B8 OpenGL texture in comptime, and found out that packed struct is not as packed as I initially assumed. Specifically, despite having no padding between structure fields, there’s padding at the end of the struct.

extern struct, on the other hand, is ‘fully packed’. Compare:

const ColrPacked = packed struct { r: u8, g: u8, b: u8 };
const packed_pixels: [128 * 128]ColrPacked = undefined;
const ColrExtern = extern struct { r: u8, g: u8, b: u8 };
const extern_pixels: [128 * 128]ColrExtern = undefined;
std.debug.print("@bitSizeOf(ColrPacked) = {}, @sizeOf(ColrPacked) = {}\n", .{@bitSizeOf(ColrPacked), @sizeOf(ColrPacked)});
std.debug.print("@sizeOf(packed_pixels) = {}\n\n", .{@sizeOf(@TypeOf(packed_pixels))});
std.debug.print("@bitSizeOf(ColrExtern) = {}, @sizeOf(ColrExtern) = {}\n", .{@bitSizeOf(ColrExtern), @sizeOf(ColrExtern)});
std.debug.print("@sizeOf(extern_pixels) = {}\n", .{@sizeOf(@TypeOf(extern_pixels))});

And the output is:

@bitSizeOf(ColrPacked) = 24, @sizeOf(ColrPacked) = 4
@sizeOf(packed_pixels) = 65536

@bitSizeOf(ColrExtern) = 24, @sizeOf(ColrExtern) = 3
@sizeOf(extern_pixels) = 49152

To be fair, documentation hints at this: There is no padding between fields.
Between fields, but not between instances of the struct.

But on the other hand, it warns against using extern struct for anything other than C interop: This kind of struct should only be used for compatibility with the C ABI. Every other use case should be solved with packed struct or normal struct.

So, of course, I could use something like const pixels: [128 * 128 * 3]u8, instead of extern struct { r: u8, g: u8, b: u8 }, but that’s just … awkward, innit?

I think this text is old, packed structs have been redesigned to be “fancy integers you can easily extract bit ranges from” and now extern structs are used for everything else.

4 Likes

Thanks. I take this as an official license to use extern struct wherever I need it then. :upside_down_face:
For example when I need a ‘truly packed’ struct type.

1 Like