Reputation: 1530
struct S1
{
char c;
int i;
};
struct S3
{
char c1;
struct S1 s;
double c2;
};
I am trying to calculate sizeof(S3)
, from my program it is 24. What I don't know is the offset of struct S1 inside S3, is there any rule to this offset? I thought "the offset of S1 must be N times of size of itself, i.e., N * sizeof(S1)", however, I found it is not true. Thanks for your help.
Upvotes: 2
Views: 5517
Reputation: 1051
This is because of padding within a struct. Computers don't store variables on just any address, they try to store them on multiples of 4 bytes, and if it can't fit the variable it sets them after the next multiple 4 bytes.
Address | Variable
--------|---------
1000 | char c
1001 | char d
1002 | //Empty so that the next int can occupy
1003 | // 4 bytes
1004 | int x
1005 | -
1006 | - //Filled till 1007 so next variable can
1007 | - // start from 1008
1008 |
1009 |
The C processor follows the same rules with structs so it leaves space and tries to fit variables on 4 byte space.
Please see The Lost art of Struct packing.
Upvotes: 0
Reputation: 36597
The C standards (to 2011) leave this mostly unspecified. The 2011 standard changed this.
The principle is that every data type has an alignment requirement represented by the number of bytes between successive addresses at which objects of that type may be allocated (or stored).
The address of a struct
type is also equal to the address of its first member (in all C standards, not just since 2011). A consequence of this, from 2011, is that the alignment of a struct
type will be a multiple of the alignment of its first member.
Every member of a struct
- not just the first - must also have alignment based on their type. For example, an int
member will have alignment requirement of an int
, a double
member has alignment requirement of a double
, an array has alignment requirement equal to size of the array (equal to number of elements times sizeof
element).
The weakest alignment (the smallest alignment requirement) is the alignment of char
, signed char
, and unsigned char
, which equals 1
. Larger types, naturally enough, have a larger alignment requirement.
Practically, an implementation will add padding as needed to ensure every member of a struct
meets its own alignment requirement.
The above is an over-simplification - there are other facilities introduced in the 2011 standard which I haven't described, like alignas
which affects how types and objects are aligned.
Upvotes: 1
Reputation: 223689
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.
Upvotes: 3
Reputation: 234635
The C
standard is intentionally flexible on this.
All it guarantees is (i) the address of the first element in a struct
is the same as the address of the struct
, and (ii) the data members appear in the order that they are declared in the struct
. (iii) an empty struct
will have a non-zero sizeof
. This last one means that pointer arithmetic is valid on null structures.
In particular, padding (of any amount) is allowed to be inserted between any structure member, and at the end.
Upvotes: 4