Bitpacking fun January 24, 2023 | 2 min Read

Bitpacking fun

When porting a C API to Rust, it’s important to understand the underlying structure layout rules that the C compiler uses. One such rule is the use of bitpacking, which allows for compact storage of data by packing multiple fields into a single backing field.

We recently ported a C++ library with a C API to Rust. There we encountered a bitpacked structure, that looked like this:

struct BITPACKED {
    uint8_t FieldA : 8;
    uint64_t FieldB : 1;
    uint64_t FieldC : 7;
    uint64_t FieldD : 48;
};

The structure BITPACKED contains four fields: FieldA, FieldB, FieldC, and FieldD. FieldA is defined as an 8-bit unsigned integer. FieldB, FieldC, and FieldD are all defined as 64-bit unsigned integers.

Which size would you expect for this structure? My initial guess was 8 bytes, since the compiler could pack them into one 64-bit backing field.

But according to the C standard, bitpacking is implementation-defined, meaning that the compiler is free to choose how to layout the fields in memory. GCC and Clang will pack this structure into one 64-bit packing field.

But our target, the Microsoft Visual C++ (MSVC) compiler has a specific set of rules for bitpacking structures, that might suprise the reader (it also surprised the writer of the C++ library, who inteded to bitpack the structure into one 64-bit field).

MSVC will only bitpack fields that are of the same size into the same backing field. This means that FieldA is stored into one 8-bit backing field and FieldB, FieldC and FieldD into another 64-bit backing field. Since the second field needs to be aligned to 8 bytes, the resulting structure will have a size of 16 bytes.

So the resulting structure in Rust looked something like this:

#[repr(C)]
pub struct BITPACKED {
    FieldA: u8,
    Packed: u64,
}

In conclusion, understanding the layout rules of bitpacked structures is crucial when porting a C API to Rust, as it can affect the size and alignment of the data in memory. Always check the documentation of the specific compiler you’re using, as the rules for bitpacking can vary between compilers.

Nils Hasenbanck

Nils Hasenbanck

Nils Hasenbanck is the founder of Tsukisoft GmbH and a senior developer. His passion is building technically elegant, easy to maintain …