C Language Structure padding


Example

Suppose this struct is defined and compiled with a 32 bit compiler:

struct test_32 {
    int a;      // 4 byte
    short b;    // 2 byte
    int c;      // 4 byte    
} str_32;

We might expect this struct to occupy only 10 bytes of memory, but by printing sizeof(str_32) we see it uses 12 bytes.

This happened because the compiler aligns variables for fast access. A common pattern is that when the base type occupies N bytes (where N is a power of 2 such as 1, 2, 4, 8, 16 — and seldom any bigger), the variable should be aligned on an N-byte boundary (a multiple of N bytes).

For the structure shown with sizeof(int) == 4 and sizeof(short) == 2, a common layout is:

  • int a; stored at offset 0; size 4.
  • short b; stored at offset 4; size 2.
  • unnamed padding at offset 6; size 2.
  • int c; stored at offset 8; size 4.

Thus struct test_32 occupies 12 bytes of memory. In this example, there is no trailing padding.

The compiler will ensure that any struct test_32 variables are stored starting on a 4-byte boundary, so that the members within the structure will be properly aligned for fast access. Memory allocation functions such as malloc(), calloc() and realloc() are required to ensure that the pointer returned is sufficiently well aligned for use with any data type, so dynamically allocated structures will be properly aligned too.

You can end up with odd situations such as on a 64-bit Intel x86_64 processor (e.g. Intel Core i7 — a Mac running macOS Sierra or Mac OS X), where when compiling in 32-bit mode, the compilers place double aligned on a 4-byte boundary; but, on the same hardware, when compiling in 64-bit mode, the compilers place double aligned on an 8-byte boundary.