Question
In C, why can the sizeof operator return a value for a struct that is larger than the total of the sizeof values of its individual members?
For example, why might a structure occupy more memory than you would expect by simply adding the sizes of all its fields together?
Short Answer
By the end of this page, you will understand why sizeof(struct) is often larger than the sum of its members in C. You will learn about memory alignment, padding bytes, and how compilers lay out structures in memory for performance and correctness. You will also see examples, common mistakes, and practical ways to inspect and reason about struct size.
Concept
In C, a struct groups multiple values into one type. It may seem natural to assume that the size of a structure should be exactly the sum of the sizes of its members, but that is often not true.
The main reason is alignment.
Different data types usually have preferred memory boundaries where they can be accessed more efficiently. For example:
- a
charoften has alignment 1 - an
intoften has alignment 4 - a
doubleoften has alignment 8
To satisfy these alignment requirements, the compiler may insert padding bytes between members or at the end of the structure.
Why alignment matters
Processors are often faster when data is stored at addresses aligned to the data type's natural boundary. On some systems, misaligned access is slower. On others, it can even cause hardware faults.
So the compiler arranges structure members like this:
- Place each member at an address that satisfies its alignment requirement.
- Insert padding if necessary before the next member.
- Possibly add padding at the end so that arrays of that structure are also properly aligned.
Example idea
Suppose this structure exists on a system where int is 4 bytes and aligned to 4 bytes:
struct Example {
char a;
int b;
};
auses 1 bytebuses 4 bytes- But
busually wants to start at an address divisible by 4
So the compiler may insert 3 padding bytes after a.
That makes the total size:
- 1 byte for
a - 3 bytes of padding
- 4 bytes for
b - total: 8 bytes
Not 5.
End padding also matters
Consider:
struct Item {
int id;
char flag;
};
This might look like 4 + 1 = 5 bytes. But the compiler may make it 8 bytes instead:
id: 4 bytesflag: 1 byte- trailing padding: 3 bytes
Why add padding at the end? Because if you create an array of struct Item, every element should start at a properly aligned address.
Important point
The C language does not guarantee one exact byte layout across all systems. Structure layout depends on:
- compiler
- target architecture
- ABI rules
- member order
- alignment requirements of each type
That is why sizeof(struct) is about the actual memory layout chosen by the compiler, not just the raw sum of field sizes.
Mental Model
Think of a struct like packing objects into storage boxes on a shelf.
- A small item like a
charis like a coin. - A larger item like an
intis like a book that must sit flat on a shelf section of a certain width.
If you put a coin down first and then want to place a book, you may need to leave some empty space so the book starts in the correct position. That empty space is padding.
At the end of the box, you may also leave some space so that if you line up many identical boxes in a row, each box starts neatly at the right boundary. That is trailing padding.
So sizeof(struct) measures the full box, including the empty spaces needed for neat and efficient placement, not just the items inside it.
Syntax and Examples
In C, you use sizeof to measure the size of a type or object.
sizeof(int)
sizeof(struct MyStruct)
sizeof(variable)
Example 1: Padding between members
#include <stdio.h>
struct Example {
char a;
int b;
};
int main(void) {
printf("sizeof(char) = %zu\n", sizeof(char));
printf("sizeof(int) = %zu\n", sizeof(int));
printf("sizeof(struct Example) = %zu\n", sizeof(struct Example));
return 0;
}
A common result is:
sizeof(char) = 1
sizeof(int) = 4
sizeof(struct Example) = 8
Even though 1 + 4 = 5, the structure may be 8 bytes because of 3 padding bytes inserted before b.
Example 2: Member order affects size
#include <stdio.h>
struct A {
char c;
int i;
char d;
};
struct B {
int i;
char c;
char d;
};
int main(void) {
printf("sizeof(struct A) = %zu\n", sizeof(struct A));
printf("sizeof(struct B) = %zu\n", sizeof(struct B));
return 0;
}
On many systems:
struct Amay be 12 bytesstruct Bmay be 8 bytes
This happens because grouping larger members first can reduce padding.
Example 3: Inspect offsets with offsetof
#include <stdio.h>
#include <stddef.h>
struct Example {
char a;
int b;
char c;
};
int main(void) {
printf("offset of a: %zu\n", offsetof(struct Example, a));
printf("offset of b: %zu\n", offsetof(struct Example, b));
printf("offset of c: %zu\n", offsetof(struct Example, c));
printf("sizeof(struct Example): %zu\n", sizeof(struct Example));
return 0;
}
This helps you see where each member starts in memory.
Step by Step Execution
Consider this example:
#include <stdio.h>
struct Sample {
char x;
int y;
};
int main(void) {
struct Sample s;
printf("%zu\n", sizeof(s));
return 0;
}
Let us walk through what often happens on a system where int is 4 bytes and aligned to 4 bytes.
Step 1: Start the struct at offset 0
The structure begins at memory offset 0.
Step 2: Place x
char x;
xneeds 1 byte- it is placed at offset
0
Current used space: 1 byte.
Step 3: Place y
int y;
yneeds 4 bytesyshould start at an offset divisible by 4- the next free offset is
1, which is not aligned forint
So the compiler inserts padding at offsets 1, 2, and 3.
Now y starts at offset 4 and occupies offsets 4 to 7.
Step 4: Total size so far
The structure now uses offsets 0 through 7, so its size is 8 bytes.
Memory layout view
| Offset | Content |
|---|---|
| 0 | x |
| 1 | padding |
| 2 | padding |
| 3 | padding |
| 4 | y byte 1 |
| 5 | y byte 2 |
| 6 | y byte 3 |
| 7 | y byte 4 |
Final result
sizeof(struct Sample) == 8
Even though the members only add up to 5 bytes, the actual structure size is 8 because alignment rules require padding.
Real World Use Cases
Understanding struct padding matters in many practical situations.
Binary file formats
If you write a struct directly to a file, padding bytes become part of the file layout. This can make the file format compiler-dependent and non-portable.
Network protocols
When sending binary data over a network, relying on raw struct layout is risky. Different systems may use different padding and alignment rules.
Embedded systems
Memory is often limited, so unnecessary padding can matter. Developers may reorder fields to reduce wasted space.
Performance-sensitive code
Alignment can improve CPU performance. Sometimes a slightly larger struct is faster because aligned accesses are more efficient.
Interfacing with hardware or foreign code
When matching a C struct with hardware registers, operating system APIs, or code written in another language, exact layout matters. Developers must understand alignment and packing rules carefully.
Real Codebase Usage
In real projects, developers usually do not just ask "what is the sum of the fields?" They care about layout, portability, and intent.
Common patterns
- Reordering fields to reduce padding
- Using
offsetofto inspect layout when necessary - Avoiding direct serialization of raw structs
- Defining explicit binary formats instead of relying on compiler layout
- Adding static checks in low-level code
Example: reorder to reduce wasted space
struct LessEfficient {
char a;
int b;
char c;
};
struct MoreEfficient {
int b;
char a;
char c;
};
The second version may use less memory on many systems.
Example: validating assumptions
#include <assert.h>
struct Header {
int id;
short type;
short flags;
};
int main(void) {
assert(sizeof(struct Header) == 8);
return 0;
}
This kind of check can be useful in low-level code, but it should only be used when the target platform assumptions are intentional.
Example: explicit serialization
Instead of writing a struct directly:
fwrite(&header, sizeof header, 1, file);
many codebases prefer to write each field in a defined format so the data stays portable and predictable.
Common Mistakes
Mistake 1: Assuming member sizes always add up exactly
Broken assumption:
struct Data {
char tag;
int value;
};
/* Wrong expectation: sizeof(struct Data) == 5 */
Why it happens:
- ignores alignment and padding
How to avoid it:
- always use
sizeof(struct Data)if you need the real size - do not manually guess struct size
Mistake 2: Using raw structs as portable file or network formats
Broken approach:
fwrite(&data, sizeof data, 1, file);
Why it is risky:
- layout can differ across compilers and platforms
- padding bytes may be included
- endianness may also differ
How to avoid it:
- serialize each field explicitly
- define exact byte-level formats
Mistake 3: Forgetting trailing padding in arrays
struct Item {
int id;
char flag;
};
A beginner may expect an array of 10 items to use 10 * 5 = 50 bytes. But if sizeof(struct Item) is 8, the array uses 80 bytes.
How to avoid it:
- use
sizeof(struct Item)when calculating array memory
Mistake 4: Using packed structs without understanding the trade-offs
Some compilers support packed structures, for example with compiler-specific attributes or pragmas.
Problem:
- packed structs can reduce size
- but they may cause slower access or even unsafe access on some hardware
How to avoid it:
- only use packing when exact layout is required
- treat packing as compiler-specific and platform-sensitive
Mistake 5: Assuming layout is identical everywhere
struct Example {
char a;
long b;
};
The size of long and its alignment can vary between systems.
How to avoid it:
- do not hard-code assumptions unless you control the platform
- check your compiler and target ABI if exact layout matters
Comparisons
| Concept | What it means | Includes padding? | Portable across systems? |
|---|---|---|---|
| Sum of member sizes | Add sizeof for each field manually | No | No |
sizeof(struct T) | Actual memory size chosen by compiler | Yes | Depends on platform |
offsetof(struct T, member) | Position of a member inside the struct | Shows layout gaps indirectly | Depends on platform |
| Packed struct | Compiler-specific layout with reduced/removed padding | Often less or none | Less portable |
sizeof(member sum) vs sizeof(struct)
- Sum of members is just a rough estimate.
sizeof(struct)is the real amount of memory an object of that type uses.
Normal struct vs packed struct
| Type | Advantage | Disadvantage |
|---|---|---|
| Normal struct | Efficient aligned access, standard behavior | May waste space due to padding |
| Packed struct | Smaller memory layout | Can be slower, unsafe on some systems, compiler-specific |
Member order comparison
| Layout style | Result |
|---|---|
| Small and large fields mixed randomly | Often more padding |
| Larger fields first, smaller fields later | Often less padding |
Cheat Sheet
sizeof(struct T)
offsetof(struct T, member)
Key rules
sizeof(struct)may be larger than the sum of member sizes.- The extra space usually comes from padding.
- Padding is added to satisfy alignment requirements.
- Padding can appear:
- between members
- at the end of the struct
- Member order can change the final size.
- Arrays of structs rely on the struct size including any trailing padding.
Example
struct X {
char a;
int b;
};
Common layout:
aat offset 0- padding at offsets 1 to 3
bat offset 4- total size: 8
Tips
- Use
sizeof(struct T)for real size. - Use
offsetofto inspect member positions. - Do not assume raw struct layout is portable.
- Reorder fields if reducing padding matters.
- Be careful with compiler-specific packed structs.
Common edge cases
long, pointers, anddoublemay have different sizes on different systems.- Trailing padding matters for arrays.
- Exact layout depends on compiler and architecture.
FAQ
Why is sizeof(struct) bigger than the sum of its fields in C?
Because the compiler may add padding bytes to satisfy alignment requirements for faster or valid memory access.
What is padding in a struct?
Padding is unused space inserted by the compiler between members or at the end of a structure.
Why is padding added at the end of a struct?
Trailing padding helps ensure that each element in an array of structs starts at a properly aligned address.
Can I remove struct padding?
Sometimes, with compiler-specific packing features or by reordering members. But removing padding can reduce performance or cause portability problems.
Does every compiler produce the same struct size?
No. Struct layout can vary by compiler, architecture, and ABI.
How can I see where struct members are stored?
Use offsetof() from <stddef.h> to inspect member offsets.
Should I write structs directly to files or sockets?
Usually no, unless you fully control the platform and layout. Explicit serialization is safer and more portable.
Mini Project
Description
Build a small C program that compares the expected sum of structure member sizes with the actual sizeof result. This project helps you see padding and alignment in action and teaches you how member order affects memory usage.
Goal
Create a program that prints member sizes, member offsets, and total struct sizes for two similar structs with different field orders.
Requirements
- Define two structs containing the same members in different orders.
- Print the
sizeofof each member type used. - Print the
offsetofvalue for each member in both structs. - Print the total
sizeofof each struct. - Show which struct is more memory-efficient on your system.
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.