Categories
c c++ c++-faq sizeof struct

Why isn’t sizeof for a struct equal to the sum of sizeof of each member?

822

Why does the sizeof operator return a size larger for a structure than the total sizes of the structure’s members?

11

  • 20

    See this C FAQ on memory alighnment. c-faq.com/struct/align.esr.html

    Apr 26, 2013 at 12:40

  • 66

    Anecdote: There was an actual computer virus that put its code within struct paddings in the host program.

    – Elazar

    Sep 2, 2013 at 17:58


  • 9

    @Elazar That’s impressive! I would never have thought it possible to use such tiny areas for anything. Are you able to provide any more details?

    – OmarL

    Nov 14, 2016 at 18:59

  • 3

    @Wilson – I’m sure it involved lots of jmp.

    Jun 27, 2017 at 21:59

  • 7

    See structure padding, packing: The Lost Art of C Structure Packing Eric S. Raymond

    – EsmaeelE

    Dec 9, 2017 at 13:53


758

This is because of padding added to satisfy alignment constraints. Data structure alignment impacts both performance and correctness of programs:

  • Mis-aligned access might be a hard error (often SIGBUS).
  • Mis-aligned access might be a soft error.
    • Either corrected in hardware, for a modest performance-degradation.
    • Or corrected by emulation in software, for a severe performance-degradation.
    • In addition, atomicity and other concurrency-guarantees might be broken, leading to subtle errors.

Here’s an example using typical settings for an x86 processor (all used 32 and 64 bit modes):

struct X
{
    short s; /* 2 bytes */
             /* 2 padding bytes */
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 3 padding bytes */
};

struct Y
{
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
    short s; /* 2 bytes */
};

struct Z
{
    int   i; /* 4 bytes */
    short s; /* 2 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */

One can minimize the size of structures by sorting members by alignment (sorting by size suffices for that in basic types) (like structure Z in the example above).

IMPORTANT NOTE: Both the C and C++ standards state that structure alignment is implementation-defined. Therefore each compiler may choose to align data differently, resulting in different and incompatible data layouts. For this reason, when dealing with libraries that will be used by different compilers, it is important to understand how the compilers align data. Some compilers have command-line settings and/or special #pragma statements to change the structure alignment settings.

18

  • 45

    I want to make a note here: Most processors penalize you for unaligned memory access (as you mentioned), but you can’t forget that many completely disallow it. Most MIPS chips, in particular, will throw an exception on an unaligned access.

    Sep 23, 2008 at 4:27

  • 41

    The x86 chips are actually rather unique in that they allow unaligned access, albeit penalized; AFAIK most chips will throw exceptions, not just a few. PowerPC is another common example.

    Sep 23, 2008 at 7:08

  • 7

    Enabling pragmas for unaligned accesses generally cause your code to balloon in size, on processors which throw misalignment faults, as code to fix up every misalignment has to be generated. ARM also throws misalignment faults.

    Sep 23, 2008 at 11:16

  • 33

    Unaligned data access is typically a feature found in CISC architectures, and most RISC architectures do not include it (ARM, MIPS, PowerPC, Cell). In actually, most chips are NOT desktop processors, for embedded rule by numbers of chips and the vast majority of these are RISC architectures.

    Oct 19, 2008 at 1:51

  • 7

    @WayneO The amount of padding is always enough to make sure that whatever is next is aligned according to its size. So, in X, there’s 2 bytes of padding after the short to ensure the 4 byte int starts on a 4 byte boundary. In Y, there’s 1 byte padding after the char to make sure the 2 byte short starts on a 2 byte boundary. Since the compiler cannot know what might be after a struct in memory (and it could be many different things), it prepares for the worst and inserts enough padding to make the struct a multiple of 4 bytes. X needs 3 bytes to get to 12, Y only needs 1 for 8.

    – 8bittree

    Feb 17, 2017 at 17:42

241

Packing and byte alignment, as described in the C FAQ here:

It’s for alignment. Many processors can’t access 2- and 4-byte
quantities (e.g. ints and long ints) if they’re crammed in
every-which-way.

Suppose you have this structure:

struct {
    char a[3];
    short int b;
    long int c;
    char d[3];
};

Now, you might think that it ought to be possible to pack this
structure into memory like this:

+-------+-------+-------+-------+
|           a           |   b   |
+-------+-------+-------+-------+
|   b   |           c           |
+-------+-------+-------+-------+
|   c   |           d           |
+-------+-------+-------+-------+

But it’s much, much easier on the processor if the compiler arranges
it like this:

+-------+-------+-------+
|           a           |
+-------+-------+-------+
|       b       |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           |
+-------+-------+-------+

In the packed version, notice how it’s at least a little bit hard for
you and me to see how the b and c fields wrap around? In a nutshell,
it’s hard for the processor, too. Therefore, most compilers will pad
the structure (as if with extra, invisible fields) like this:

+-------+-------+-------+-------+
|           a           | pad1  |
+-------+-------+-------+-------+
|       b       |     pad2      |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           | pad3  |
+-------+-------+-------+-------+

4

  • 2

    Now what is the use of memory slots pad1, pad2 and pad3.

    Dec 26, 2016 at 6:07

  • 7

    @YoYoYonnY that’s not possible. The compiler is not allowed to reorder struct members although gcc has an experimental option to do that

    – phuclv

    Mar 2, 2017 at 2:57

  • @EmmEff this might be wrong but I do not quite get it: why is there no memory slot for the pointer in the arrays?

    Dec 7, 2019 at 23:25

  • 2

    @BalázsBörcsök These are constant-size arrays, and so their elements are stored directly in the struct at fixed offsets. The compiler knows all this at compile time so the pointer is implicit. For example, if you have a struct variable of this type called s then &s.a == &s and &s.d == &s + 12 (given the alignment shown in the answer). The pointer is only stored if the arrays have a variable size (e.g., a was declared char a[] instead of char a[3]), but then the elements have to be stored somewhere else.

    – kbolino

    Mar 31, 2020 at 13:57


31

If you want the structure to have a certain size with GCC for example use __attribute__((packed)).

On Windows you can set the alignment to one byte when using the cl.exe compier with the /Zp option.

Usually it is easier for the CPU to access data that is a multiple of 4 (or 8), depending platform and also on the compiler.

So it is a matter of alignment basically.

You need to have good reasons to change it.

10

  • 7

    “good reasons” Example: Keeping binary compatibility (padding) consistent between 32-bit and 64-bit systems for a complex struct in proof-of-concept demo code that’s being showcased tomorrow. Sometimes necessity has to take precedence over propriety.

    – Mr.Ree

    Dec 8, 2008 at 4:58

  • 2

    Everything is ok except when you mention the Operating System. This is an issue for the CPU speed, the OS is not involved at all.

    Jan 12, 2009 at 2:51

  • 7

    Another good reason is if you’re stuffing a datastream into a struct, e.g. when parsing network protocols.

    – ceo

    Oct 20, 2009 at 15:18

  • 1

    @dolmen I just pointed out that “it is easier for the Operatin System to access data” is incorrect, since the OS doesn’t access data.

    Aug 24, 2013 at 17:44

  • 2

    It is better to use #pragma pack(1) – it is supported by MSVC, gcc and clang, which makes your code more portable

    – mvp

    Mar 20, 2021 at 21:04