CLOSE
Updated on 17 Jun, 202514 mins read 4 views

For systems programmers working close to the hardware, memory layout is a crucial factor in designing efficient and correct programs. Poor memory alignment leads to hard-to-find bugs, performance degradation, and sometimes outright crashes — especially in embedded or cross-platform contexts.

This article explores the core principles of memory alignment and padding in C++, explains why misalignment hurts, and shows how to optimize struct layout safely.

What Is Memory Alignment?

Memory alignment refers to placing data at memory addresses that are multiples of the data’s size or required alignment.

  • On a 32-bit system:
    • Data is typically accessed in 4-byte words
    • Types like int and float (4 bytes) must be stored at addresses divisible by 4
  • On a 64-bit system:
    • Many types (like double or pointers) align to 8 bytes

Why Alignment Matters

1. CPU Efficiency

Aligned access lets the CPU fetch data in a single operation. Unaligned access can cause:

  • Multiple memory fetches
  • Bit shifting and recombination
  • Stall cycles

2. Hardware Restrictions

Some architectures (like ARM, SPARC, MIPS) do not allow unaligned access at all:

  • Accessing an int at a non-4-byte-aligned address may cause a hardware exception

3. Data Corruption & Crashes

Casting misaligned memory into structs or pointers can lead to:

  • Corrupted reads/writes
  • Cache line fragmentation
  • Segmentation faults

Misaligned Scenario

Struct without padding (assuming no alignment):

struct BadLayout {
    bool b;    // offset 0
    int  i;    // offset 1 (misaligned!)
    float f;   // offset 5 (also misaligned!)
};

On a 32-bit system:

  • int and float must be aligned to 4-byte boundaries (offsets 0, 4, 8, etc.)
  • In this layout:
    • int starts at offset 1misaligned
    • float starts at offset 5misaligned
  • bool is fine at offset 0

Let’s say the CPU wants to read i at offset 1 (misaligned 4-byte access):

❌ Unaligned Read (int at offset 1):

  • CPU needs two memory fetches:
    • First: read from address 0–3
    • Second: read from address 4–7
  • Then it reconstructs the value by combining the relevant bytes

This is:

  • Slower
  • Can cause a hardware exception on strict CPUs (e.g., ARM)
  • May even result in incorrect data if you're casting

So to save the CPU cycles, and to optimize, compiler adds the padding the align the members.

What is Padding?

Padding refers to extra, unused bytes inserted by the compiler to satisfy alignment constraints.

Example:

struct Misaligned {
    bool b;     // offset 0
    int  i;     // offset 1 (!!! misaligned)
    float f;    // offset 5 (!!! also misaligned)
};

On a 32-bit system:

  • int and float must be aligned to 4-byte boundaries
  • Since i is at offset 1, it's misaligned

How Compilers Fix This: Padding

To fix the above struct, compilers insert padding bytes to restore alignment.

struct Aligned {
    bool b;     // offset 0
    char pad[3]; // offset 1–3 (compiler-added padding)
    int  i;     // offset 4
    float f;    // offset 8
};

Now:

  • i and f are 4-byte aligned
  • Struct size is 12 bytes, but only 9 bytes are used
  • The rest is padding

Example: Size of structure

#include <iostream>

struct S {
    char c;
    int i;
};

int main() {
    std::cout << "Size of S: " << sizeof(S) << "\n";
    std::cout << "Alignment of S: " << alignof(S) << "\n";
}

Output:

Size of S: 8
Alignment of S: 4

Disable Padding

In GCC and clang__attribute__((packed)) is used as extension to disable the padding.

It tells the compiler to remove all padding between members of a struct/class.

That means:

  • Members are placed back-to-back
  • Alignment rules are not enforced
  • Structure becomes compact in memory

Example:

#include <iostream>

struct S {
    char c;
    int i;
}__attribute__((packed));

int main() {
    std::cout << "Size of S: " << sizeof(S) << "\n";
    std::cout << "Alignment of S: " << alignof(S) << "\n";
}

Output:

Size of S: 5
Alignment of S: 1

⚠️ Dangers of packed

RiskDescription
Unaligned accessMay crash on hardware like ARM, MIPS, or SPARC
Slow memory fetchUnaligned reads take 2x+ more cycles on some CPUs
Undefined behaviorCasting pointers to misaligned structs is risky
Compiler-specificNot standard C++, may need porting effort