How structure-padding in C/C++ actually works

Saptarshi DeySaptarshi Dey
5 min read

In case you're not familiar with structure padding or inheritance, I'd suggest you go through these videos first as they will come in handy

Why use Structure Padding in the first place? 🤷‍♂️️

The reason is simple, to increase the efficiency of the system. Every data type in C will have alignment requirements (in fact it is mandated by processor architecture, not by language). A processor will have processing-word length as that of data bus size. On a 32-bit machine, the processing word size will be 4 bytes whereas on a 64-bit machine, the processing word size will be 8 bytes.

Coding time 🥳

Let's consider the following code

#include <stdio.h>

struct Goku{
    int x,y;
    char b,c;
};

int main(){
    printf("Goku size = %lu bytes\n",sizeof(struct Goku));
    return 0;
}

What will be the output of this code?

🤔
"Goku size = 10 bytes" I hear you say. And that would be correct if the padding length was 1. But as we will see shortly, that's not the case

This is the actual output of the code

Goku size = 12 bytes

But how? 🤷‍♂️️

You can't see this image because you're stupid (just kidding)

The reason is because the structure is arranged in memory like this

4-bytes4-bytes4-bytes
4-bytes integer4-bytes integer1-byte char + 1-byte char + 2-bytes free space

But why 4-bytes? 🤷‍♂️️

This is because 4-bytes is the size of the largest primary datatype (int) in the structure. Makes sense? Let's see another example.

Consider the following code

#include <stdio.h>

struct Goku{
    double d;
    char b,c;
};

int main(){
    printf("Goku size = %lu bytes\n",sizeof(struct Goku));
    return 0;
}

It's similar to the previous code but instead of 2 integers of 4-bytes, we have 1 double of 8-bytes. The following is the output

Goku size = 16 bytes

The reason is because the structure is arranged in memory like this

8-bytes8-bytes
8-bytes double1-byte char + 1-byte char + 6-bytes free space

But why 8-bytes? 🤷‍♂️️

This is because 8-bytes is the size of the largest primary datatype (double) in the structure.

Let's consider another example

#include <stdio.h>

struct Goku{
    char b;
    double d;
    char c;
};

int main(){
    printf("Goku size = %lu bytes\n",sizeof(struct Goku));
    return 0;
}

Output

Goku size = 24 bytes

Explanation

8-bytes8-bytes8-bytes
1-byte char + 7-bytes free space8-bytes double1-byte char + 7-bytes free space

Do you see a pattern here?

But what if we use a user-defined datatype inside another structure?

So far, we have seen how padding works for primitive datatypes. Now let's see what happens when we use a user-defined datatype inside another structure.

Consider the following code

#include <stdio.h>

struct Goku{
    double d;
    char b,c;
};

struct Vegeta{
    struct Goku a,b;
    char c;
};

int main(){
    printf("Goku size = %lu bytes\n",sizeof(struct Goku));
    printf("Vegeta size = %lu bytes\n",sizeof(struct Vegeta));
    return 0;
}

You might think the padding size would be 16-bytes since that's the largest datatype. But Goku is not a primitive datatype. Here's the output of the given code

Goku size = 16 bytes
Vegeta size = 40 bytes

It turns out, the padding size is 8 because that's the size of the largest primary datatype in Goku as well as Vegeta since Vegeta contains 2 instances of Goku

So size of Vegeta before padding = 2*16 + 2 = 34
Size of Vegeta after padding = 34 + 8 - (34 % 8) = 42 - 2 = 40
💡
Replace the double with 2 integers of 4-bytes and check if the answer correlates with this logic

Some common datatypes and their sizes

Data typeSize in bytes
unsigned char1
signed char1
unsigned int4
signed int4
unsigned short int2
signed short int2
unsigned long int8
signed long int8
float4
long float or double8
long double16

How to prevent structure padding from wasting space in memory?

Note: Structure padding was originally designed for the CPU to achieve quicker memory read and write operations and lower memory access time. If we disable it, the speed of execution of our program might suffer. So there's a tradeoff.

If we want to disable structure padding then we need to use a preprocessor named pragma which is used to enable or disable certain features of the compiler.

Consider the following code

#pragma pack(1)
#include <stdio.h>

struct Goku{
    double d;
    char b,c;
};

struct Vegeta{
    struct Goku a,b;
    char c;
};

int main(){
    printf("Goku size = %lu bytes\n",sizeof(struct Goku));
    printf("Vegeta size = %lu bytes\n",sizeof(struct Vegeta));
    return 0;
}

This is the same code as the second example but this time, we use the pragma pre-processor. This essentially tells the compiler to use 1 (or whatever you put as the argument) as the default padding size.

The following is the output of the given code

Goku size = 10 bytes
Vegeta size = 21 bytes

As you can see, the size of the structures is exactly equal to the sum of the member variables

Exercise for the reader

How structure-padding affects the size of inherited datatypes?

I could answer this question in this blog but it is quite lengthy as it is. So we will leave that for some other time

Goku Smile GIFs | Tenor

That's it folks 🙂️ If you find my content useful then kindly like and share

2
Subscribe to my newsletter

Read articles from Saptarshi Dey directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Saptarshi Dey
Saptarshi Dey

Programming and mathematics geek with an interest in chess, anime, and geopolitics