Optimizing C Structure Layout with alignas and offsetof
C structs include invisible padding for alignment. Learn how alignas and offsetof let you measure and control layout to avoid memory waste and false sharing.
10 Jul 2026, 19:26 UTC

Structs rarely occupy exactly the sum of their members. The compiler inserts padding to satisfy hardware alignment, and that invisible slack can waste memory in large arrays or cause false sharing when two hot fields land on the same cache line. The useful takeaway is to measure layout with offsetof and control it with alignas, rather than guessing.
Alignment is not cosmetic. Unaligned accesses can fault on some architectures and always cost extra cycles. In concurrent code, two independent counters sharing a 64-byte cache line force repeated invalidations even though the data is logically separate.
When padding costs more than you expect
Hardware loads memory in cache lines, typically 64 bytes on modern x86 and ARM. A 4-byte int is usually required to start at an address divisible by 4, an 8-byte double at a multiple of 8. If a char precedes an int, the compiler adds 3 padding bytes so the int stays aligned.
In a single instance this is trivial. In an array of millions of structs, slack compounds. Reordering members by decreasing alignment is the first low-risk win, but it does not guarantee cache isolation for hot fields.
Controlling placement with alignas
C11 introduced alignas to request a specific alignment for an object or member. The request must be a power of two and not exceed the implementation maximum; exceeding it is undefined behavior.
SIMD types often need 16 or 32-byte alignment for optimal execution. For concurrency, aligning independent counters to a cache line prevents false sharing.
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
struct Metrics {
alignas(64) uint64_t counter_a;
alignas(64) uint64_t counter_b;
};
int main(void) {
printf("sizeof(struct Metrics) = %zu\n", sizeof(struct Metrics));
printf("alignof(struct Metrics) = %zu\n", alignof(struct Metrics));
printf("offsetof counter_b = %zu\n", offsetof(struct Metrics, counter_b));
return 0;
}
Compile with a C11 mode, for example gcc -std=c11 -Wall -Wextra file.c. The alignas specifier applies to each member individually. The compiler will insert padding between counter_a and counter_b so counter_b starts on the next 64-byte boundary. Check the result with alignof and offsetof at compile time or in a small diagnostic build.
Auditing layout with offsetof
offsetof from stddef.h returns the byte offset of a member from the start of its struct, including any compiler-inserted padding. It is the reliable way to verify reordering or alignas effects.
| Member | Typical size | Offset after alignas(64) |
|---|---|---|
| counter_a | 8 | 0 |
| counter_b | 8 | 64 |
Verification steps to run locally:
- Compile with -std=c11 to ensure alignas is standard, not a vendor extension.
- Print alignof for the struct and members to confirm the requested alignment is honored.
- Print offsetof for each member to see actual gaps.
On pre-C11 toolchains alignas is unavailable and developers fall back to non-standard extensions such as __attribute__((aligned(n))) or #pragma pack. Those are not portable.
Trade-offs you have to accept
Alignment increases memory density cost. Aligning a 1-byte field to 64 bytes wastes 63 bytes per instance. In large arrays this reduces the number of useful items that fit in L1/L2 cache and can increase cache misses.
Over-aligning also raises struct size, which can increase stack usage and allocation overhead. Align to the architecture maximum only when the hardware or API requires it, such as for SIMD loads or DMA buffers.
Limitations to keep in mind:
- alignas values larger than the implementation maximum cause undefined behavior.
- Manual alignment does not change the natural alignment of the type; it only raises it.
- Padding is still inserted to satisfy the strictest member alignment within the struct.
Actionable closing: start by measuring with offsetof and sizeof on your target compiler and flags. Reorder members by size, then apply alignas only to the few hot fields that benefit from cache line isolation or hardware requirements. Re-measure size and offsets after each change and compare cache behavior in your workload.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.