2
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.

HuangJie
  • 1,488
  • 1
  • 16
  • 33
  • 1
    Why don't you just use `offsetof(struct S3, s)`? – EOF Jul 12 '16 at 13:58
  • @EOF I know how to get this value, but I don't know the principle. How does the computer decide the offset of S1, is there any rule? – HuangJie Jul 12 '16 at 14:00
  • Why do you want to know the offset? – fukanchik Jul 12 '16 at 14:00
  • http://stackoverflow.com/a/119128/669576 – 001 Jul 12 '16 at 14:01
  • If you know how to ge the offset then why do you ask how to get it? If you want to know how members are allocated, what have you done to find out yourself? What **specifically** did youi not understand in the explanations available on the web? – too honest for this site Jul 12 '16 at 14:04
  • 1
    If you want to know how alignment is handled (i.e. how the offsets and sizes are calculated), see any online article in data alignment. Note that there are several strategies and that these may vary from compiler to compiler, from platform to platform and from user to user. – Rudy Velthuis Jul 12 '16 at 14:20

4 Answers4

4

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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
3

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.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    Your assumptions about the layout of `struct S3` are likely incorrect. `struct S1` only needs to be aligned on a `sizeof(int)` boundary, so there is likely only 3 bytes of padding after `char c1` in `struct S3`. The rest of the padding is *after* `struct S1 s`, since `double c2` must be aligned to `sizeof(double)`, which is likely `8`. – EOF Jul 12 '16 at 14:43
  • @EOF You're right, that makes more sense than aligning a `struct` on the full size. Edited to reflect. – dbush Jul 12 '16 at 15:10
  • Caution about alignment "need". Typical default padding occurs to promote efficient code, not minimal data spacing. – chux - Reinstate Monica Jul 12 '16 at 15:19
  • @chux: No, padding occurs to conform to explicit correctness requirements in C regarding alignment. – EOF Jul 12 '16 at 17:00
  • @EOF. Disagree. Many compilers support a keyword like `packed` to address this. This is used to make structures with minimal padding. (e.g. space savings at the cost of lower performance code) Yes padding does occur to meet _minimum_ alignment requirements of the various types. The point is additional padding may be used in a `struct`, like for faster data access. I have noticed this additional padding is the typical default unless a `packed` like keyword is used. – chux - Reinstate Monica Jul 12 '16 at 17:16
  • @chux: things like `__attribute__((packed))` and its ilk are decidedly non-standard. C11 draft standard n1570: *6.2.8 Alignment of objects 1 Complete object types have alignment requirements which place restrictions on the addresses at which objects of that type may be allocated.*. It's a requirement for conforming code. No if or but. – EOF Jul 12 '16 at 17:18
  • @EOF Padding can also be controlled by compiler options and need not be in the source code - of course this is a wide ranging effect. Not to loose sight of the issue "Variables of a particular type needs to be aligned such that their address is a multiple of the size of the type." un-clearly overstates alignment/padding needs. Example: should code be compiled for an underlying processor with an 8-byte wide data bus, it is certain there would be no need for any padding is a `struct`. – chux - Reinstate Monica Jul 12 '16 at 17:28
1

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.

Peter
  • 35,646
  • 4
  • 32
  • 74
0

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Chandrahas Aroori
  • 955
  • 2
  • 14
  • 27
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/16815714) – McGrady Jul 25 '17 at 02:03
  • I'm sorry. I will edit it, I'm new to stackoverflow.. :/ – Chandrahas Aroori Jul 25 '17 at 02:07