kj4tmp
September 19, 2024, 3:49pm
8
Packed structs are represented in memory using a backing integer. Access to fields is essentially a convenience feature around bitshifts. This means the backing integer is subject to the same alignment rules as regular integers. This means you will have padding in the most significant bits (highest memory address for little endian systems, lowest memory address for big endian systems).
readStruct is confusion and should probably be removed or modified from its current state in the std lib.
I use a lot of packed structs in my library because I have a binary protocol that can be defined using the little endian layout of a packed struct. You can find some examples of conversion functions etc here.
//! Serilization and deserialization utilities specific to EtherCAT.
const std = @import("std");
const assert = std.debug.assert;
const native_endian = @import("builtin").target.cpu.arch.endian();
pub fn packedSize(comptime T: type) comptime_int {
comptime assert(isECatPackable(T));
return @divExact(@bitSizeOf(T), 8);
}
pub fn isECatPackable(comptime T: type) bool {
if (@bitSizeOf(T) % 8 != 0) return false;
return switch (@typeInfo(T)) {
.Struct => |_struct| blk: {
// must be a packed struct
break :blk (_struct.layout == .@"packed");
},
.Int, .Float => true,
.Union => |_union| blk: {
This file has been truncated. show original
I also created this issue:
opened 04:56AM - 16 Jul 24 UTC
docs
### Zig Version
0.14.0-dev.66+1fdf13a14
### Steps to Reproduce and Observed Be… havior
The docs say packed structs have defined in-memory layout but do not fully describe what that in-memory layout is, especially when considering host endianness, non-byte aligned, and not-byte-width fields.
### Expected Behavior
I expected the docs to describe the in-memory layout of structs under the effects of host-endianness, non-byte aligned, and not-byte-width fields.
And you may be interested in this issue as well
opened 07:19AM - 25 Sep 22 UTC
bug
contributor friendly
standard library
### Zig Version
0.9.1 (windows, chocolatey),0.10.0-dev.4166+cae76d829
### … Steps to Reproduce
1. create file repro.zig
``` zig
/// repro.zig
const std = @import("std");
const expect = std.testing.expect;
const PackedStruct = packed struct {
a: u48,
b: u48,
c: u16,
};
test "reading a packed struct" {
const file = try std.fs.cwd().openFile("repro.zig", .{});
const reader = file.reader();
_ = try reader.readStruct(PackedStruct);
const pos_from_reading_struct = try reader.context.getPos();
try reader.context.seekTo(0);
_ = try reader.readBytesNoEof(@bitSizeOf(PackedStruct) / 8);
const pos_from_reading_bytes = try reader.context.getPos();
std.log.warn("{}, {}", .{ pos_from_reading_struct, pos_from_reading_bytes });
try expect(pos_from_reading_struct == pos_from_reading_bytes);
}
```
2. ```zig test repro.zig```
### Expected Behavior
Test passes.
Log output should be ```14. 14```
### Actual Behavior
Test fails. Log output is ```16, 14```.
This is because ```@sizeOf(PackedStruct)``` is 16.
However, using sizeOf in readStruct is undesirable for reading consecutive packed structs, because now the seeker position is wrong, affecting future reads downstream. To correct this manually, the developer has to check if packed struct requires padding, and manually wind the seeker back using ```seekBy```.
4 Likes