Visualizing Bit-Packed Structures in GCC

 In Cortex-M, embedded C, programming, Windows

Why is this even an Issue?

Little-endian, big-endian, native bit orders, there are lots of subtle or not-so-subtle differences between computer architectures. Depending on how we visualize our memory map, and how we natively read words (left-to-right, right-to-left, top-to-bottom, etc.) impact our ability to grasp how the bits flow. On top of that, the C standard does not specify how bit-packing is done. This means that it might change between compilers, or even compiler revisions. GCC even has this nice warning that says:

note: offset of packed bit-field ‘<em>&lt;your struct member name here></em>’ has changed in GCC 4.4

So, using bit-packed structures that are persistent or shared between systems is dangerous, because it introduces opportunitites for errors to crop up over time as compilers change. It may also not pack the same on different hardware. Because of this, it is suggested that we are very careful when we use bit-packed structures.

You probably landed here because you were given a bit-packed structure, or have a bit packed structure that you are either trying to make a structure to access the members with, or you are trying to figure out the actual bit packing and making functions to read/write the structure that have defined behavior. This article talks about how to visualize on little-endian systems bit-packing with GCC 11.4.0. This was tested on an ARM Cortex-M core (set to little-endian) and an Intel x64 system.

Visualizing the Bits

We normally think about things in bytes. Visualizing bit-packing in bytes is not where we should start. Think about filling a funnel. The bottom of the funnel is the least significant bit (LSB) of the lowest byte address. From there, bits are poured in member-by-member, starting with the LSB of each member. The figure below gives a small example.

If we take those bytes and lay them down, how many people traditionally view the memory map, It’s not as clear.

Traps for New Players

One particular trap to watch out for is if you want a member bit-packed, it must have the

:<em>width</em>
at the end of the variable, like
uint8_t somevar:8;
. If you leave that off, it will not bit-pack the variable, but start it at the next location it normally would. Giving the structure the packed attribute,
__attribute__((packed))
, only does byte packing, not bit packing.

Leave a Comment

Contact Us

We're not around right now. But you can send us an email and we'll get back to you, asap.

Start typing and press Enter to search