WTF GCC, why pad my structs?

Suppose you have a structure in C as follows

struct fields {
    uint8_t f1;
    uint16_t f2;
    uint8_t f3;
}

What do you think the size of this structure is? It should be 4 bytes, right? However if you print the output of sizeof operator on this struct, it will give you 6 bytes. Where do the extra 2 bytes come from? This is where the concept of "structure padding" comes in.

C compilers are good at making access to data fast. To do this, this is the general rule they follow: A data type of N-byte length should be placed at an address where address % N == 0 (that's the modulo operator).

Now imagine our example struct starts at byte address 20.

 address: 20  21  22  23
          --  --  --  --
 field  : f1  f2  f2  f3

Fair enough. See the address of f2?. The size of f2 itself is 2 bytes. It violates the rule that f2_address % sizeof(f2) == 0 because 21 % 2 = 1.

To forcibly comply with the rule, the C compiler "pads" a byte after f1 (before f2, to be precise). So f2 lies on address 22, not 21. We have accounted for the first extra byte denoted as x0 below.

 address: 20  21  22  23  24
          --  --  --  --  --
 field  : f1  x0  f2  f2  f3

But why and where a second extra byte? Imagine that instead of a lonely struct lying around in memory, there is an array of two of them.

 address: 20  21  22  23  24  25  26  27  28  29
          --  --  --  --  --  --  --  --  --  --
 field  : f1  x0  f2  f2  f3  f1  x0  f2  f2  f3
                              ^ start second struct

Oops! The field f2 of second struct again fails to comply with the modulo rule. The compiler has a way around this too. This time it pads another byte (denoted as x1 below) after field f3.

 address: 20  21  22  23  24  25  26  27  28  29  30  31
          --  --  --  --  --  --  --  --  --  --  --  --
 field  : f1  x0  f2  f2  f3  x1  f1  x0  f2  f2  f3  x1
                                  ^ start second struct

Now we know why our structs are taking more memory than we actually hoped for. There are few tricks to minimize the padding, potentially saving memory on big arrays. Keep these points in mind while writing a struct layout:

  • The biggest data type in a struct (uint16_t in our example) dictates the alignment of the struct itself. What this means is that the "N" in the modulo rule for the struct itself is equal to the N of the biggest data type. You can use the alignof operator to find that out at runtime, if needed.
#include <stdio.h>
#include <stdint.h>
#include <stdalign.h>

struct fields {
    uint16_t f1;
    uint16_t f2;
    uint8_t f3;
    uint32_t f4;
};

int main(void)
{
    printf("struct size: %zu\n",sizeof(struct fields));   //12
    printf("struct align: %zu\n",alignof(struct fields)); //4
    return 0;
}
  • The compiler will continue to put together variables as long as they fit within the struct's biggest data type. If there is still any space left, it will be padded.

In the following struct f1, f2 and f3 easily fit within uint32_t so it will have no padding at all.

struct fields {
    uint16_t f1;
    uint8_t f2;
    uint8_t f3;
    uint32_t f4;
};

On the other hand, in the following struct f1, f2 and f3 do fit within uint32_t but there is still space for one more byte. So there will be a padded byte after f3.

struct fields {
    uint8_t f1;
    uint8_t f2;
    uint8_t f3;
    uint32_t f4;
};
  • Any field failing to fit within the space will create a whole new slot for itself. In the following struct there will be 3 bytes padded after f3. Again, those 3 bytes could have been used by other fields.
struct fields {
    uint16_t f1;
    uint16_t f2;
    uint8_t f3;
    uint32_t f4;
};
  • A general way of minimizing padding is to put the bigger data types first.

Keep in mind you can always disable structure padding, though you wouldn't want to do this if performance and portability means anything to you. Modern x86_64 processors' performance is not affected by misaligned memory access [1].


  1. https://wr.informatik.uni-hamburg.de/_media/teaching/wintersemester_2013_2014/epc-14-haase-svenhendrik-alignmentinc-paper.pdf ↩︎

Jawad Ahmad

Engineering student. Embedded software developer. Expert Dota 2 player (not really). Local swimming champ. 👻

Read More