1. 7

  2. 10

    Fun fact, the Rust compiler does not have to arrange struct fields in the order they are defined, therefore it can pack for you without you having to do anything. If you want a stable ABI, you write #[repr(C)] on the line before the struct keyword, this gives you C-style control over the field order (https://doc.rust-lang.org/reference/type-layout.html#the-c-representation).

    1. 6

      More detailed article from 2018 with a very similar title:


      1. 4

        Posting it here as well in a comment on the article but I recently found this: https://github.com/Viladoman/StructLayout

        1. 2

          This is a good intro to a subject which isn’t probably isn’t addressed often enough.

          An additional thing worth mentioning is that only short <= int <= long is guaranteed, so you should be using guaranteed-sized primitive types, like uint16_t from <cstdint> and static_assert to verify your struct size and offsets, especially if you’re trying to match a specific binary format.

          1. 2

            The easiest way to pack a struct is to order them from largest to smallest

            Though note that packing struct members from smallest to largest will also result in an optimally packed struct.

            1. 2

              This is one of the biggest sources of perf overhead in CHERI. When we make pointers 128 bits, but leave long and uint64_t 64 bits, a lot of structures end up with padding. I ended up adding a warning to clang when padding exceeds a certain amount (either as total number of bytes or percentage of the total). There were a few really bad cases. One benchmark we ran used a data structure made entirely out of {int, pointer, int} structures. It was originally written for a 32-bit platform, where the struct was 12 bytes. On an LP64 architecture, it had a bit of padding and ended up being 24 bytes for 16 bytes of data. On CHERI, it was 48 bytes for 24 bytes of data: 50% padding. Rearranging it to {pointer, int, int} got our overheads down a lot!