HuangJie
HuangJie

Reputation: 1530

sizeof struct inside struct

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

Answers (4)

Chandrahas Aroori
Chandrahas Aroori

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

Peter
Peter

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

dbush
dbush

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

Bathsheba
Bathsheba

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

Related Questions