CPUs load data fastest (or only) at addresses that are multiples of its size. The compiler therefore inserts invisible padding bytes into structs, so sizeof is often larger than the sum of the members.
#include <stdio.h>
#include <stddef.h>
struct Bad { char a; int b; char c; }; /* 1 + 3 pad + 4 + 1 + 3 pad */
struct Good { int b; char a; char c; }; /* 4 + 1 + 1 + 2 pad */
int main(void) {
printf("Bad = %zu bytes\n", sizeof(struct Bad));
printf("Good = %zu bytes\n", sizeof(struct Good));
printf("offsets in Bad: a=%zu b=%zu c=%zu\n",
offsetof(struct Bad, a), offsetof(struct Bad, b), offsetof(struct Bad, c));
printf("alignof(int)=%zu alignof(double)=%zu\n", _Alignof(int), _Alignof(double));
return 0;
}Bad = 12 bytes
Good = 8 bytes
offsets in Bad: a=0 b=4 c=8
alignof(int)=4 alignof(double)=8The rules
Each member is aligned
A member of type
Tstarts at an offset that is a multiple of_Alignof(T)— padding is inserted before it if needed.The struct is aligned
The struct’s alignment is the largest alignment of any member.
Tail padding
sizeofis rounded up to a multiple of the struct’s alignment, so that in an array every element is aligned too.Order is kept
The compiler never reorders members — the first member is always at offset 0.
| Offset | 0 | 1 | 2 | 3 | 4–7 | 8 | 9–11 |
|---|---|---|---|---|---|---|---|
struct Bad | a | pad | pad | pad | b | c | pad |
Minimising padding
#include <stdio.h>
struct Messy { char c1; double d; char c2; int i; short s; };
struct Sorted { double d; int i; short s; char c1; char c2; }; /* largest first */
int main(void) {
printf("%zu %zu\n", sizeof(struct Messy), sizeof(struct Sorted));
return 0;
}32 16Packing (compiler extension)
#include <stdio.h>
#include <stdint.h>
struct __attribute__((packed)) Header { /* GCC/Clang; MSVC uses #pragma pack(1) */
uint8_t type;
uint32_t length;
uint16_t flags;
};
int main(void) {
printf("packed size = %zu\n", sizeof(struct Header));
return 0;
}packed size = 7Explicit alignment (C11)
#include <stdio.h>
#include <stdalign.h>
#include <stdint.h>
struct Cacheline { alignas(64) char data[64]; }; /* avoid false sharing between threads */
int main(void) {
alignas(16) float v[4] = {0};
printf("%zu %zu %d\n", alignof(struct Cacheline), sizeof(struct Cacheline),
(int)((uintptr_t)v % 16 == 0));
return 0;
}64 64 1What is structure padding and why does it exist?
What is sizeof(struct { char c; double d; })?
How do you find the offset of a member?