Skip to content

34 Intermediate The Hundred

The Struct That Shrank

same three members, different order, different bill

struct Wasteful {
    char a;
    int b;
    char c;
};
struct Tidy {
    int b;
    char a;
    char c;
};

int main() {
    std::cout << "sizeof(Wasteful) = " << sizeof(Wasteful) << "   a@" << offsetof(Wasteful, a)
              << " b@" << offsetof(Wasteful, b) << " c@" << offsetof(Wasteful, c) << '\n';
    std::cout << "sizeof(Tidy)     = " << sizeof(Tidy) << "   b@" << offsetof(Tidy, b) << " a@"
              << offsetof(Tidy, a) << " c@" << offsetof(Tidy, c) << '\n';
}

Run it. Two structs, the same three members — the same size?

Answer

No. Shuffling three declarations cut a third off the struct (GCC 11.5, x86-64):

sizeof(Wasteful) = 12   a@0 b@4 c@8
sizeof(Tidy)     = 8   b@0 a@4 c@5

Why

Every type has an alignment — on x86-64 an int wants an address divisible by 4 — and the compiler may not reorder members, so its only tool is padding. Wasteful puts a at 0, burns three bytes so b can start at 4, drops c at 8, then pads the tail to 12 to keep the size a multiple of its 4-byte alignment. Tidy leads with the int and both chars slot in behind it at 4 and 5 — 8 bytes, still not 6, because tail padding never goes away. Those padding bytes hold whatever garbage was there, so std::memcmp can report two logically equal objects as different. -Wall -Wextra says nothing, but add -Wpadded and GCC narrates every hole: "padding struct to align 'Wasteful::b'".

The fix

Declare members from largest alignment down to smallest and the holes mostly close up:

struct Tidy {
    int b;      // widest first, then the small stuff fills in behind it
    char a;
    char c;
};              // 8 bytes, not 12

#pragma pack(push, 1) squeezes the original to 6 bytes, but you pay: unaligned access is slower on x86-64 and illegal on some architectures. (alignas(1) is no escape hatch: it cannot weaken a type's natural alignment — GCC 11.5 leaves the struct at 12 bytes.)

Takeaway: member order is part of the layout — the compiler pads, it never reorders.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry