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.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.