SystemsAlso on YouTube

Why 1 + 4 + 1 Equals 12: Struct Padding in C vs Rust

The same three fields add up to 6 bytes on paper and 12 bytes inside a C struct. Why the CPU reads memory in fixed chunks, where C inserts padding, and how Rust reclaims the wasted space.

3 min readLuChang Ning

Why 1 + 4 + 1 Equals 12#

Tip
Watch the video version of this article: https://youtu.be/pEfLTRwb7MY

In the world of mathematics, 1 + 4 + 1 equals 6. In systems programming, the same three numbers routinely add up to 12. The compiler has not failed basic arithmetic — it is obeying a set of rules laid down by the hardware itself.

To understand why, we need to meet the boss: the CPU.

The CPU reads memory in fixed chunks#

The CPU is extraordinarily fast — and extraordinarily picky. It does not like reading memory one byte at a time. Instead, it grabs memory in fixed chunks, usually 4 or 8 bytes at a time, and it expects certain values to begin at certain addresses.

And your CPU hates working twice.

An integer that straddles two chunks has to be assembled from two separate reads. So the hardware simply refuses: on most architectures, a 4-byte int must start at an address that is a multiple of 4. This rule is called alignment, and every compiler you will ever use is forced to respect it.

C: what you see is what you get#

C's philosophy is simple: WYSIWYG — what you see is what you get. The language respects your authority, and lays out memory in the exact order you wrote your code.

Consider this struct:

c
struct Layout {
    char a;   // 1 byte
    int  b;   // 4 bytes
    char c;   // 1 byte
};

printf("%zu\n", sizeof(struct Layout));  // 12

Three fields, six bytes on paper — but sizeof reports 12. Here is what the compiler actually produced:

text
offset:  0    1    2    3    4    5    6    7    8    9   10   11
         [ a ][ P ][ P ][ P ][        b        ][ c ][ P ][ P ][ P ]

The integer b must begin at a multiple of 4, so it cannot start at offset 1. The compiler stuffs 3 bytes of padding — useless filler — between a and b. And because the struct's total size must also be a multiple of its largest member's alignment, 3 more padding bytes trail c.

The CPU gets what it demands. You pay for it in memory.

Rust: the compiler is allowed to do better#

Now look at Rust. Its philosophy is different: "If you don't specify, I'll make it better."

rust
// Rust's default layout: the compiler MAY reorder fields.
struct Layout {
    a: u8,   // 1 byte
    b: i32,  // 4 bytes
    c: u8,   // 1 byte
}

// C-compatible layout: exact field order, padding included.
#[repr(C)]
struct CLayout {
    a: u8,
    b: i32,
    c: u8,
}

The Rust compiler looks at that wasteful C layout and sees a professional organizer's opportunity: the gap behind a is exactly large enough to hold c. By default, Rust reserves the right to reorder fields, and it uses that freedom to tuck the small fields into the padding — shrinking the struct from 12 bytes to 8, automatically, without changing a single line of your logic.

The keyword is may. Rust's default layout is deliberately unspecified; it is an optimization, not a promise. The moment you need the layout to be a contract — for FFI, for serialization, for matching a file format — you opt out with #[repr(C)] and get the exact C behavior back, padding and all.

Control versus efficiency#

So is Rust smarter than C? Not necessarily. It is a different trade-off.

C gives you absolute control: the memory layout is yours to reason about, byte for byte, which is why C still rules the kernel and every ABI on the planet. Rust gives you efficiency by default, and asks you to say so explicitly when you need the control back.

In computing, there is no magic — only carefully chosen trade-offs. The next time a sizeof surprises you, remember: the padding is not waste. It is the price of a deal between your code and the CPU.

Note
If this article helped "align" your understanding, there is a video version with visuals: https://youtu.be/pEfLTRwb7MY

Watch the video version

This article is also available as a video on @luchangningCodeHero.

Keep reading

Enjoyed this deep dive?

Read another article, or watch the video version on YouTube.