Skip to main content

Alignment and offsetof

Alignment ensures data is placed at memory addresses divisible by its size, improving CPU access speed. Padding fills gaps to maintain alignment.

Alignment Basics

struct Example {
char c; // 1 byte
int i; // 4 bytes
};

sizeof(Example); // 8, not 5! (3 bytes padding after c)

Why: CPU reads memory in aligned chunks (typically 4 or 8 bytes). Misaligned access is slower or crashes on some platforms.


Alignment Requirements

#include <iostream>

std::cout << alignof(char) << "\n"; // 1
std::cout << alignof(int) << "\n"; // 4
std::cout << alignof(double) << "\n"; // 8
std::cout << alignof(void*) << "\n"; // 8 (64-bit)

Rule: Type must be aligned to multiple of its size.


Struct Padding

struct Bad {
char c; // Offset 0, size 1
// 3 bytes padding
int i; // Offset 4, size 4
char c2; // Offset 8, size 1
// 7 bytes padding (for array alignment)
};
sizeof(Bad); // 16 bytes

struct Good {
int i; // Offset 0, size 4
char c; // Offset 4, size 1
char c2; // Offset 5, size 1
// 2 bytes padding
};
sizeof(Good); // 8 bytes (50% savings!)
Tip

Order members largest to smallest to minimize padding.


offsetof Macro

Get member offset within struct:

#include <cstddef>

struct Point {
int x;
int y;
int z;
};

std::cout << offsetof(Point, x) << "\n"; // 0
std::cout << offsetof(Point, y) << "\n"; // 4
std::cout << offsetof(Point, z) << "\n"; // 8

Controlling Alignment

alignas (C++11)

// Align to 16 bytes
struct alignas(16) Aligned {
int x;
int y;
};

sizeof(Aligned); // 16 (8 data + 8 padding)
alignof(Aligned); // 16

// Align member
struct Container {
alignas(64) char buffer[64]; // Cache-line aligned
};

Packed Structs

// Remove padding (compiler-specific)
struct __attribute__((packed)) Packed {
char c;
int i;
char c2;
};
sizeof(Packed); // 6 (no padding)

// MSVC syntax
#pragma pack(push, 1)
struct Packed {
char c;
int i;
};
#pragma pack(pop)
warning

Packed structs can cause crashes on some architectures and are slower due to unaligned access.


Practical Examples

Network Protocol

// Bad: padding wastes bandwidth
struct Message {
char type; // 1 byte
int length; // 4 bytes (3 padding before)
char data[100];
}; // 108 bytes (3 wasted)

// Better: pack or reorder
#pragma pack(push, 1)
struct Message {
char type;
int length;
char data[100];
}; // 105 bytes
#pragma pack(pop)

Cache Optimization

// Align to cache line (64 bytes) to prevent false sharing
struct alignas(64) Counter {
std::atomic<int> value;
char padding[60]; // Fill cache line
};

Summary

  • Alignment: Memory addresses divisible by type size
  • Padding: Filler bytes for alignment
  • sizeof: Includes padding
  • offsetof: Member offset in struct
  • alignas: Control alignment
  • Order members: Large → small minimizes padding
// Minimize padding
struct Optimized {
double d; // 8 bytes
int i; // 4 bytes
short s; // 2 bytes
char c; // 1 byte
// 1 byte padding
}; // 16 bytes total