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?