3

I'm working with C structs including bit-fields such as this one:

struct beeper_general_t
{
  uint1_t enable : 1;
  uint32_t : 7;
  enum2_t loudness : 2;
  uint32_t : 22;
  enum2_t status : 2;
};

For debugging purposes, I need to know how the compiler (GCC) lays out the struct in memory (exact position and width of each field).

What I'm doing right now is write some test code like this one:

struct beeper_general_t my_struct;
for(;;) {
    my_struct.enable = 0;
    my_struct.enable = 1;
}

Then I look at the generated assembly code to get the information I want. As this is a rather tedious process, I wonder whether there's a simpler way of visualizing the actual layout of structs in memory.

3
  • 2
    How about you pass -g to GCC so that it generates debug information? Commented Jul 31, 2014 at 8:52
  • How does that get me information about the layout of the structs? Commented Jul 31, 2014 at 13:35
  • 1
    Compile code that printf all struct fields one per line, and then decompile with objdump -S. It will contain the offsets of each field of the struct. Commented Jul 19, 2015 at 18:51

4 Answers 4

1

The generated assembly, or alternatively the compiler documentation are the typical way to go about this. It wouldn't be a big deal to write a function that dumps the memory occupied by a struct along with the address offsets of all the members, but you'd need to redo that for every new struct.

Sign up to request clarification or add additional context in comments.

1 Comment

Address offsets would be difficult to retrieve, as bitfields don't have addresses.
1

I hope all types uint1_t, uint32_t etc are same to exploit the bitfields properly. If not, you should make it same as:

struct beeper_general_t
{
  uint32_t enable : 1;
  uint32_t : 7;
  uint32_t loudness : 2;
  uint32_t : 22;
  uint32_t status : 2;
};

6.7.2.1 Structure and union specifiers

[10] An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined.The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.

If you are want a specific layout, please prefer bit shifting as layout of bitfields is unspecified and may change with compiler, target etc.

If you want enable to be 1 bit, loudness to be 2 bit etc, using bitfield is a wise choice. If you want enable to be specifically at bit0 or bit31 or for similar requirement, you should avoid bitfield.

2 Comments

Thanks, but my question was more about how to get information about the struct layout that was chosen by the compiler. It's clear to me that almost everything about bit-fields is implementation-dependend, and that they should generally be avoided.
OK, then I would prefer Method1: dump memory around my_struct(in program or using GDB), Method2: use -S switch and analyze the difference in assembly by incrementally setting the bitfields.
1

pahole is useful for the purpose of viewing struct layout. Sadly because uint1_t and enum2_t aren't standard types I have to substitute something else in but here's some example output:

struct beeper_general_t
{
        uint32_t enable : 1;
        uint16_t : 7;
        uint32_t loudness : 2;
        uint64_t : 22;
        uint32_t status : 2;
};

Results in this pahole output:

struct beeper_general_t {
    uint32_t                   enable:1;             /*     0:31  4 */
    uint32_t                   loudness:2;           /*     0:22  4 */

    /* XXX 29 bits hole, try to pack */

    uint32_t                   status:2;             /*     4:30  4 */

    /* size: 8, cachelines: 1, members: 3 */
    /* bit holes: 1, sum bit holes: 29 bits */
    /* bit_padding: 30 bits */
    /* last cacheline: 8 bytes */
};

Similar questions:

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.