ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.

Home Page:https://ziglang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Document Effects of Endianness on Packed Structs

kj4tmp opened this issue · comments

commented

Zig Version

0.14.0-dev.66+1fdf13a14

Steps to Reproduce and Observed Behavior

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.

commented

Not sure how complete documentation is (I assume you mean langref).
In status-quo, a packed struct is treated as a single integer that concatenates its fields' bits starting from the lowest-value bit.
So packed struct {a: A, b: B} stores a: A in its lowest-value bits and b: B its highest-value bits.
Endianness affects the mapping of lower-value-byte vs higher-value-byte to lower-address-byte vs higher-address byte. So differences will be observable in the addresses of the constituent bytes.

If the packed struct fits into one byte, there is no difference. If the packed struct has more than 8 bits, its backing bytes will be exactly flipped in address layout, while the backing integer value will still be the same (in the respective native endianness). (Note: Backing bytes may be ceiled, f.e. @sizeOf(u24) may be 4, meaning the u24 is represented as 4 bytes in memory.)

probably also worth mentioning that padding bytes are added for allignment of packed structs, for example this assertion fails:

const EthernetHeader = packed struct(u112) {
        dest_mac: u48,
        src_mac: u48,
        ether_type: u16,

        comptime {
            std.debug.assert(@sizeOf(@This()) == 112 / 8);
        }
    };