kj4tmp
July 21, 2024, 7:06am
1
Am I using writeStructEndian wrong or is this a bug?
test "header write" {
const EthernetHeader = packed struct(u112) {
dest_mac: u48,
src_mac: u48,
ether_type: u16,
};
const header: EthernetHeader = .{
.dest_mac = 0xAABB_CCDD_EEFF,
.src_mac = 0x1122_3344_5566,
.ether_type = 0x88a4,
};
var buf: [64]u8 = std.mem.zeroes([64]u8);
var fbs = std.io.fixedBufferStream(&buf);
var writer = fbs.writer();
try writer.writeStructEndian(header, std.builtin.Endian.big);
std.log.warn("wrote: {x}", .{fbs.getWritten()});
// prints: { aa, bb, cc, dd, ee, ff, 11, 22, 33, 44, 55, 66, 88, a4, 0, 0 }
// the 0, 0 at the end should not be there! ^ ^ bad!!
try std.testing.expect(fbs.getWritten().len == 112 / 8);
}
The problem here is that the compiler adds alignment to integer types, which in this case adds padding zeroes. For example u112
is aligned to 16 bytes which makes
@sizeOf(u112) == 16 == @sizeOf(u128)
I think you can do the byteSwap manually and then use .writeInt(u112, @bitCast(byteSwappedStruct), .little);
kj4tmp
July 21, 2024, 7:20am
3
yeah… this assertion fails, so i think you are right about the padding zeros
const EthernetHeader = packed struct(u112) {
dest_mac: u48,
src_mac: u48,
ether_type: u16,
comptime {
std.debug.assert(@sizeOf(@This()) == 112 / 8);
}
};
kj4tmp
July 21, 2024, 7:22am
4
this makes me really question if write struct endian should even exist, it already required packed structs:
pub fn writeStruct(self: Self, value: anytype) anyerror!void {
// Only extern and packed structs have defined in-memory layout.
comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != .auto);
return self.writeAll(mem.asBytes(&value));
}
kj4tmp
July 21, 2024, 7:24am
5
or perhaps writeStructEndian should be changed to not add the padding of packed structs?