Alignment, Padding, and Object Layout
This chapter explains alignment in full: what it is, how it affects struct layout, how to query and control it, and why misaligned access is undefined behavior.
Why This Matters
Alignment is both a correctness and a performance concern. Misaligned access is UB (and can fault on some CPUs), while padding affects sizeof, cache behavior, binary compatibility, and memory usage.
Prerequisites
c.core.26— structs, padding, alignment basics.
Core Concept
Alignment
Every object type has an alignment requirement: the address of an object of that type must be a multiple of some power of two. For example, int usually has alignment 4, double usually 8, and char alignment 1.
The _Alignof operator (C11, alignof from <stdalign.h>) returns the alignment requirement of a type.
Padding
To satisfy alignment, the compiler inserts padding:
- Internal padding: between struct members.
- Trailing padding: after the last member, so arrays of the struct keep
each element aligned.
The struct's own alignment is the maximum of its members' alignments.
Object layout
For a struct, members are laid out in declaration order at increasing addresses, each at an offset that is a multiple of its alignment. The struct size is rounded up to a multiple of its alignment.
Syntax
#include <stdalign.h> /* alignof, alignas (C11) */
_Alignof(int) /* 4 on typical systems */
alignof(int) /* macro for _Alignof */
_Alignas(16) int x; /* request 16-byte alignment (C11) */
Examples
Querying alignment
#include <stdio.h>
#include <stdalign.h>
int main(void)
{
printf("alignof(char) = %zu\n", alignof(char));
printf("alignof(int) = %zu\n", alignof(int));
printf("alignof(double) = %zu\n", alignof(double));
return 0;
}
Expected output (typical LP64): 1, 4, 8.
Struct layout with padding
#include <stdio.h>
#include <stddef.h>
#include <stdalign.h>
struct S {
char a; /* offset 0, align 1 */
int b; /* offset 4 (3 bytes padding), align 4 */
char c; /* offset 8, align 1 */
}; /* size 12 (1 byte trailing padding to align 4) */
int main(void)
{
printf("sizeof = %zu, alignof = %zu\n",
sizeof(struct S), alignof(struct S));
return 0;
}
Expected output: sizeof = 12, alignof = 4.
Aligning an object explicitly
_Alignas(16) unsigned char buf[64]; /* buf is 16-byte aligned */
This is useful for SIMD (c.perf.simd) and DMA buffers.
How It Works
The compiler computes offsets at compile time. Each member is placed at the next offset divisible by its alignment. The struct is padded to its alignment. Alignment applies to objects, not just structs; a stack or heap allocation must satisfy the type's alignment.
Variations
Over-alignment
An alignment stricter than the natural one (e.g., 32 bytes for SIMD) is called over-alignment. C11 _Alignas supports it, but the underlying allocator (malloc) may not return suitably aligned memory; use aligned_alloc or posix_memalign (platform-specific).
Packed structs (non-standard)
__attribute__((packed)) (GCC/Clang) removes padding but can produce misaligned members. Accessing a misaligned member is UB.
Common Mistakes
- Assuming
sizeof(struct)is the sum of member sizes. - Assuming member offsets are portable.
- Dereferencing a pointer to a packed struct's member (misaligned).
- Assuming
mallocreturns memory aligned for over-aligned types.
Undefined Behavior
- Accessing an object through a misaligned pointer is UB.
VERIFIED - Casting a
charbuffer (alignment 1) to adouble *and dereferencing when
the buffer is not 8-byte aligned is UB.
Portability
- Alignment and padding are implementation-defined.
VERIFIED _Alignof/_Alignasare C11 and later.- Packed structs are compiler extensions.
Under the Hood
CPUs load/store values most efficiently (or only) at aligned addresses. On x86, unaligned access is allowed but slower; on many ARM and RISC-V variants, unaligned access faults or requires special handling. The compiler relies on alignment guarantees to emit aligned load/store instructions.
Practical Usage
- Use
offsetofand_Alignofto reason about layout portably. - Order struct members by decreasing alignment to reduce padding (but only if
the layout is not externally constrained).
- Use
_Alignasfor SIMD/DMA buffers andaligned_allocfor over-aligned
heap memory.
Exercises
1. Write a program that prints alignof for char, short, int, long, double, and a struct containing them. 2. Reorder the members of a struct to minimize padding and verify the new sizeof. 3. Demonstrate over-alignment with _Alignas and verify the address is aligned. 4. Use a packed struct and explain the misalignment danger.
Deep Challenge
Given a set of members, derive a rule for ordering them to minimize struct size, and prove (by example and reasoning) that ordering by decreasing alignment minimizes padding. Then discuss when you should *not* reorder members (binary compatibility, clarity).
Related Concepts
c.struct.padding— struct padding.c.perf.simd— SIMD alignment.c.mem.alignment— allocation alignment.c.ffi.struct-layout— layout in FFI.
References
- ISO/IEC 9899:2018 §6.2.8 (alignment), §6.7.2.1 (struct layout),
§6.7.5 (alignas).
Verification
_Alignof/_Alignasare C11.VERIFIED- Alignment/padding are implementation-defined.
VERIFIED - Misaligned access is UB.
VERIFIED - No example was executed during generation unless noted. `Execution not
verified.`
Progress
- [ ] Read
- [ ] Understand
- [ ] Complete examples
- [ ] Complete exercises
- [ ] Complete deep challenge
Concept checkboxes
- [ ] Alignment requirements
- [ ] _Alignof/_Alignas
- [ ] Internal and trailing padding
- [ ] Struct layout
- [ ] Misaligned access UB
- [ ] Over-alignment
Mastery levels
| Concept | Current level (0–8) | Target level |
|---|---|---|
| c.obj.alignment | 0 | 6 |
| c.obj.layout | 0 | 6 |