Skip to content

Instantly share code, notes, and snippets.

@mikdusan
Last active February 19, 2020 04:00
Show Gist options
  • Save mikdusan/07c47650efd96fd674bae5843088e6a3 to your computer and use it in GitHub Desktop.
Save mikdusan/07c47650efd96fd674bae5843088e6a3 to your computer and use it in GitHub Desktop.
packed_struct.md -- the main document is a comment because big fonts suck
@mikdusan
Copy link
Author

mikdusan commented Jan 24, 2020

>>>> related

key comments:

»»»» packed struct

The set of features that distinguish packed struct from struct are:

  • field order matches declaration order
  • default field alignment is align(0)
  • default no padding or hidden bits between fields
const Foo = packed struct {
                // byto: @byteOffsetOf
                // bito: @bitOffsetOf
                //
                // byto  bito  *align(A:O:H)
                // ---------------------------------
    a: u12,     //   0     0    1:0:2
    b: u1,      //   1    12    1:4:1
    c: u32,     //   1    13    1:5:5
    d: u4,      //   5    45    1:5:2
    e: bool,    //   6    49    1:1:1
    f: u4,      //   6    50    1:2:1
};

assert(@alignOf(Foo) == 1);
assert(@sizeOf(Foo) == 7);
assert(@bitSizeOf(Foo) == 54);
assert(@bitOffsetOf(Foo, "f") == 50);

»» whole-structure memory layout size

  • memory layout size is measured in integral units of bytes and is returned by @sizeOf(__T)
  • value based on (@bitOffset(__T, __last_field) + @bitSizeOf(__last_field)) and extended to meet alignment requirement

»» whole-structure bit-size

  • bit-size is measured in integral units of bits and is returned by @bitSizeOf(__T)
  • value is @bitOffsetOf(__T, __last_field) + @bitSizeOf(__last_field)

»» whole-structure alignment

  • alignment is measured in integral units of bytes and is returned by @alignOf(__T)
  • value is equal to its most-aligned field and is returned by @alignOf(__T)
  • if @alignOf(__T) == 0 and @bitSizeOf(__T) != 0 alignment is 1

»» field alignment

  • alignment is measured in integral units of bytes and is returned by @fieldAlignOf(__T, __field_name)
  • fields default to align(0)
  • fields may specify byte-alignment explicitly and must be a power-of-2
const Foo = packed struct {
    a: u32, // align(0:0)
    turtle: *const align(1) u32, // align(0)
    rabbit: *const align(1) u32 align(@alignOf(usize)), // align(8)
}

If necessary, layout size is padded to the next multiple of its most-aligned field's alignment.

const Foo = packed struct {
    a: u7,
    b: u3,
}
assert(@sizeOf(Foo) == 2);
assert(@bitSizeOf(Foo) == 10);

const Bar0 = packed struct {
    a: u3 align(16),
}
assert(@sizeOf(Bar0) == 16);
assert(@bitSizeOf(Bar0) == 3);

const Bar1 = packed struct {
    a: u7,
    b: u32 align(16),
}
assert(@sizeOf(Bar1) == 32);
assert(@bitSizeOf(Bar1) == 131);

const Bar2 = packed struct {
    a: u7,
    b: u3 align(16),
    c: u7,
}
assert(@sizeOf(Bar2) == 48);
assert(@bitSizeOf(Bar2) == 263);

»» field pointers

  • pointers to non-byte-aligned fields (fields with @bitOffsetOf() % 8 != 0) have special meta-information shown as an extended alignment tuple: *align(__A:__O:__H)
  • this information reveals the load/store data sizes (the "host-integer") used to access the field
  • __H is the host-integer size in bytes
  • __O is the bit-offset from host-integer's 0-bit
  • __A is the host-integer alignment in bytes
  • if __A is not explicitly shown it's value is 0
  • if only __A is shown the field is 8-bit aligned

For example, on x86_64, a u5 field could be unaligned-from-byte by 0 to 3 bits and Zig chooses the smallest possible host-integer size which is a single byte u8. Consider if the u5 field was unaligned by 4 bits. It overlaps across two bytes and the host-integer would then be u16.

»» field byte-offset

  • @byteOffsetOf(__T, __field_name) will return the offset from base-of-structure to the field's host-integer

»» TODO

  • define well-defined memory layout
  • syntax to specify aggregated fields are not to be packed?

@mikdusan
Copy link
Author

mikdusan commented Jan 25, 2020

  • TODO: incorporate this into doc (from IRC)
here is what it should mean if it is missing: if it is missing then the alignment of the address,
which is the address of the host integer, is @alignOf(@IntType(false, 1 * 8)), where 1
is the host integer byte count (the 1 in *align(:3:1))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment