Why sizeof(struct) is not equal to the sum of sizeof(fields)? Full breakdown

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

How is this possible? Introduction to the sizeof paradox

\n\n

Imagine: you create a simple structure in C++ with two fields — char (1 byte) and int (4 bytes). It's logical to assume its size will be 5 bytes. You write the code, call sizeof and... get 8 bytes. "Nonsense!" you think. "Has the compiler gone mad?"

\n\n

This question is one of the most popular on Stack Overflow (over 200,000 views). And it's not about a compiler error. It's about how the processor and RAM actually work at a low level. In this article, we will break down structure alignment in C++, the concept of padding, and learn to predict the real size of structures. And most importantly — learn how to control it when it's really needed.

\n\n

Why 1 + 4 ≠ 5? The physics of the process

\n\n

Modern processors do not read memory byte by byte. They work with "words" — blocks of 4, 8, or 16 bytes (depending on the architecture). If a 4-byte integer (int) is located at an address that is not a multiple of 4, the processor will have to make two memory accesses instead of one to read that number, and then "assemble" it from two pieces. This is catastrophically slow.

\n\n

To avoid this, the compiler inserts "empty" bytes (padding) between the fields of the structure. It aligns each field to an address that is a multiple of its size. This is called natural alignment.

\n\n
// A simple example that surprises everyone\n#include <iostream>\n\nstruct Example {\n    char c;   // 1 byte\n    int  i;   // 4 bytes\n};\n\nint main() {\n    std::cout << "Size of char: " << sizeof(char) << std::endl;    // 1\n    std::cout << "Size of int: "  << sizeof(int)  << std::endl;    // 4\n    std::cout << "Size of struct: " << sizeof(Example) << std::endl; // 8 (!)\n    return 0;\n}
\n\n

How does this look in memory? c occupies byte 0. Bytes 1, 2, 3 are padding. And i starts at byte 4. Total: 1 (c) + 3 (empty) + 4 (i) = 8 bytes.

\n\n

Alignment rules: how the compiler makes decisions

\n\n

The compiler follows simple but strict rules. Knowing them, you will be able to predict the size of a structure without running the program.

\n\n
    \n
  • Rule 1: The order of fields is preserved. The compiler does not rearrange fields in memory (although some compilers may do this during optimization, the standard does not guarantee it).
  • \n
  • Rule 2: Each field is aligned to an address that is a multiple of its size. char (1 byte) can be anywhere. short (2 bytes) — at even addresses. int (4 bytes) — at addresses that are multiples of 4. double (8 bytes) — at addresses that are multiples of 8.
  • \n
  • Rule 3: The size of the entire structure must be a multiple of the alignment of the largest field. This is necessary for arrays of structures to work correctly. If the largest variable is a double (8 bytes), then the size of the structure will be a multiple of 8.
  • \n
\n\n

Let's break down a more complex example:

\n\n
struct Complex {\n    char  a; // 1 byte\n    int   b; // 4 bytes\n    short c; // 2 bytes\n    char  d; // 1 byte\n};\n// What will sizeof be? Let's calculate together.
\n\n

Step-by-step breakdown:

\n
    \n
  • a (char) — byte 0.
  • \n
  • b (int) — must be at an address that is a multiple of 4. The next such address is 4. So, padding: bytes 1, 2, 3. Total after b: 8 bytes (0-7).
  • \n
  • c (short) — must be at an even address. Current position is 8 (even). Great. Total after c: 10 bytes (0-9).
  • \n
  • d (char) — can be anywhere. Place it at byte 10. Total after d: 11 bytes (0-10).
  • \n

Blogs

Book Recommendations