As Bathsheba said, how the compiler pads structures is not dictated by the standard. That said, here's what's most likely happening.
Variables of a particular type needs to be aligned such that their address is a multiple of the size of the type. So a 2 byte variable needs to start on a 2 byte address, a 4 byte variable starts on a 4 byte address, etc. For a struct
, the alignment is that of the largest "base" type. For an array, it's the size of the base type, not the whole array.
In struct S1
, you have a char
followed by an int
. Assuming an int
is 4 bytes, that means 3 bytes of padding are needed between c
and i
. So the struct with the implicit padding looks like this:
struct S1
{
char c; // offset 0
char padding[3]; // offset 1
int i; // offset 4
};
This give us sizeof(struct S1) == 8
.
Then in struct S3
, you have an instance of struct S1
which is 8 bytes (but has 4 byte alignment) and a double
which is most likely 8 bytes. So for them to be properly aligned, there needs to be 3 bytes of padding after c1
, then 4 more after s
. So now struct S3
with implicit padding looks like this:
struct S3
{
char c1; // offset 0
char padding[3]; // offset 1
struct S1 s; // offset 4
char padding[4]; // offset 12
double c2; // offset 16
};
We then have sizeof(struct S3) == 24
.
While a padding scheme such as this is what you're most likely to come across, the standard does not guarantee it.