How structure-padding in C/C++ actually works
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?
This is the actual output of the code
Goku size = 12 bytes
But how? 🤷♂️️
The reason is because the structure is arranged in memory like this
4-bytes | 4-bytes | 4-bytes |
4-bytes integer | 4-bytes integer | 1-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-bytes | 8-bytes |
8-bytes double | 1-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-bytes | 8-bytes | 8-bytes |
1-byte char + 7-bytes free space | 8-bytes double | 1-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
Some common datatypes and their sizes
Data type | Size in bytes |
unsigned char | 1 |
signed char | 1 |
unsigned int | 4 |
signed int | 4 |
unsigned short int | 2 |
signed short int | 2 |
unsigned long int | 8 |
signed long int | 8 |
float | 4 |
long float or double | 8 |
long double | 16 |
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
That's it folks 🙂️ If you find my content useful then kindly like and share
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