The present version of the C standard defines bitfield layout too strictly to allow compilers to lay them out optimally, but without sufficient detail to allow code to do much of anything if the standards said nothing about their layout.
A definition like unsigned short x:5;
implies that if there is no previous structure element, the previous structure element was not a bitfield whose declared type was a short
or unsigned short
, or the space holding it doesn't have space for another five-bit value, the compiler should create a new unnamed structure element of type unsigned short
and allocate a range of five consecutive bits to x
. If none of those conditions apply (i.e. there is a previous structure element, it's a bitfield whose declared type is short
or unsigned short
, and the space holding it has room for another five-bit bitfield), the bitfield will share the element with the previous one.
Thus, given a declaration like:
struct {
uint16_t a,b,c,d,e,f,g,h : 6;
} PACK_AS_UINT16;
a compiler would start by placing a
in a 16-bit word and then putting b
somewhere in that same word. Because c
won't fit in the same word (that would bring the total to 18 bits) the compiler must allocate another word for c
, but can pack d
in there as well. Likewise another word for e
and f
, and a fourth one for g
and h
. If the declaration had instead been:
struct {
uint32_t a,b,c,d,e,f,g,h : 6;
} PACK_AS_UINT32:
then the compiler would be able to pack a
-e
in one 32-bit word, and would put f
-h
in another (leaving 14 bits of unused space in the second word).
Note that while the optimal packing for eight 6-bit values would use three 16-bit words, such a packing would require that two of the values straddle 16-bit items. While some compilers have historically been able to accommodate that without difficulty, the present standard does not permit it.