I have a stuct a of size 16 bytes and another struct b which contains a. Why is struct b of size 40 bytes? Where is the additional padding exactly?
typedef struct {
} a;
typedef struct {
a x;
} b;
CodePudding user response:
The struct a
has 4-byte alignment since that's the largest alignment of any of its members (i.e. float
).
From there, the fields of b
are laid out with the following offsets:
w
: 0- padding: 1 - 3
x
: 4 - 19- padding: 20 - 23
y
: 24 - 31z
: 32 - 33- padding: 34 - 39
The member with the largest alignment is y
which has 8-byte alignment. This results in 4 bytes of padding between x
and y
, as well as 6 bytes of padding at the end.
The padding can be minimized by moving z
to between w
and x
. Then you would have:
w
: 0- padding: 1
z
: 2 - 4x
: 4 - 19- padding: 20 - 23
y
: 24 - 31
For a total size of 32.
Alignment is of course entirely up to the implementation, but this is what you'll most likely see. The Lost Art of C Structure Packing goes into this in much more detail.
CodePudding user response:
The algorithm compilers typically use to lay out structures is described in this answer.
For your structure a
and characteristics typical in current C implementations (described below):
- The
char
w
has an alignment requirement of 1 byte, so it needs no padding and is placed at offset 1. It occupies 1 byte. - The
float
x
has an alignment requirement of 4 bytes, so 3 bytes are needed to bring the current offset from 1 byte to 4 bytes. Then it occupies 4 bytes, giving us 8 total so far. - The
short int
y
has an alignment requirement of 2 bytes, so it needs no padding from the current offset of 8 bytes. It occupies 2 bytes, bringing the total to 10. - The
float
z
has an alignment requirement of 4 bytes, so it needs 2 bytes to bring the offset from 10 bytes to 12 bytes. It occupies 4 bytes, bringing the total to 16. - The alignment requirement of the structure is 4 bytes (the strictest alignment requirement of its members), and the current total is 16 bytes, which is already a multiple of 4, so no padding at the end is needed.
Thus the size of a
is 16 bytes.
For your structure b
:
- The
char
w
has an alignment requirement of 1 byte, so it needs no padding and is placed at offset 1. It occupies 1 byte. - The
a
x
has an alignment requirement of 4 bytes, so 3 bytes of padding are needed to bring the offset from 1 byte to 4 bytes. It occupies 16 bytes, bringing the total to 20. - The
double
y
has an alignment requirement of 8 bytes, so 4 bytes of padding are needed to bring the offset from 20 bytes to 24. It occupies 8 bytes, bringing the total to 32. - The
short int
z
has an alignment requirement of 2 bytes, so no padding is needed from the current offset of 32 bytes. It occupies 2 bytes, bringing the total to 34. - The alignment requirement of the structure is 8 bytes (the strictest alignment requirement of its members), so 6 bytes of padding is needed to bring the total size from 34 bytes to 40.
Thus the size of b
is 40 bytes.
The characteristics used are:
char
has size 1 byte and alignment requirement 1 byte. This is a fixed property of the C standard.short int
has size 2 bytes and alignment requirement 2 bytes.float
has size 4 bytes and alignment requirement 4 bytes.double
has size 8 bytes and alignment requirement 8 bytes. (Having an alignment requirement of 4 bytes instead of 8 would not be very weird; hardware might load and store doubles in 32-bit chunks and not care whether either of them were 8-byte aligned.)- The C implementation does not use more padding or stricter alignment than required by the sizes and alignment requirements of structure members. (This is not mandated by the C standard, but there is generally no reason to do otherwise.)
CodePudding user response:
You seem to understand why the size of a
is 16 bytes, and I'll also assume that you see why a
has an alignment requirement of 4 bytes (see the note about arrays in the discussion below on the alignment of b
). From that, we can see that, in b
, we will have 3 bytes of padding between w
and x
.
Now, on your platform (as on many/most), a double
has a size and alignment requirement of 8 bytes – so, after the 20 bytes up to the end of x
(1 for w
, 3 for padding and 16 for x
), we need to add 4 bytes padding between x
and y
, to align that double
. Thus, we have now added 12 bytes to our total, giving a running size (up to y
) of 32 bytes.
The z
member takes another 2 bytes (running size of 34) but, as the alignment requirement of the overall b
structure must be 8 bytes (so that, in an array of such, every element's y
will remain properly aligned), we need a further 6 bytes to reach a size (40) that is a multiple of 8.
Here is a breakdown of the memory layout:
typedef struct {
char w; // 1 byte: total = 1
// 3 bytes padding: total = 4
float x; // 4 bytes: total = 8
short int y;// 2 bytes: total = 10
// 2 bytes padding: total = 12
float z; // 4 bytes: TOTAL = 16
} a;
typedef struct {
char w; // 1 byte: total = 1
// 3 bytes padding: total = 4
a x; // 16 bytes: total = 20
// 4 bytes padding: total = 24
double y; // 8 bytes: total = 32
short int z;// 2 bytes: total = 34
// 6 bytes padding: TOTAL = 40
} b;