6

sizeof(x) returns 2 for the structure below

struct s {
    short c;
} x;

but for the structure

struct s {
    short c;
    char a;
} x;

sizeof(x) returns 4, Why?

The second one gets one padding byte (assuming short is 2 bytes long and char 1 byte long). Shouldn't the first structure have 2 padding bytes then (and thus be 4 bytes long)?

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
user3711671
  • 823
  • 1
  • 6
  • 13
  • 3
    Do you know the purpose of padding? – StoryTeller - Unslander Monica Feb 14 '19 at 12:08
  • To improve performance, but I'm not completely sure how.I assume CPUs can read memory only in multiples of their bus width so it's more efficient to read everything at once if possible. – user3711671 Feb 14 '19 at 12:16
  • When the compiler decides so. – KamilCuk Feb 14 '19 at 12:18
  • 1
    https://stackoverflow.com/questions/47324044/why-is-there-no-padding-in-the-structure-for-only-char-type-members – msc Feb 14 '19 at 12:22
  • 1
    This question is similar enough to yours, and has a nice enough answer that goes into padding. Not sure if it's a dupe though https://stackoverflow.com/questions/28928283/why-padding-are-added-if-char-comes-after-int – StoryTeller - Unslander Monica Feb 14 '19 at 12:25
  • 2
    @user3711671: The idea is simply to ensure that all elements will be aligned to addresses which are multiples of their byte sizes. As soon as you add an `int` somewhere in your struct, presuming `sizeof(int) > sizeof(short)`, compiler will have to pad the end of the struct to a multiple of `sizeof(int)`. – vgru Feb 14 '19 at 12:38
  • @Groo: Alignment requirements are not necessarily equal to or multiples of sizes. A four-byte `int` might have a two-byte alignment requirement. – Eric Postpischil Feb 14 '19 at 14:07

2 Answers2

5

The predominant use of padding is to align structure members as required by the hardware (or other aspects of the C implementation). An algorithm for laying out data in a struct is in this answer.

To answer the question in your title, when do structures not have padding: A structure does not require padding for alignment if each member’s alignment requirement is a divisor of the total size of all preceding members and of the total size of all members. (A C implementation may still add padding for reasons other than alignment, but that is a bit unusual.)

For your examples, let’s suppose, in a C implementation, short is two bytes in size and requires two-byte alignment. By definition, char is one byte and requires one-byte alignment.

Then, in struct s {short c;}:

  • c is put at the beginning of the struct. There is never any padding at the beginning.
  • If we make an array of these struct, the next struct s will begin two bytes beyond the first, and its member c will still be at a multiple of two bytes, so it is aligned correctly.
  • Therefore, we do not need any padding to make this work.

In contrast, in struct s {short c; char a;}:

  • c is put at the beginning.
  • a is put two bytes after c. This is fine, since a only requires one-byte alignment.
  • If we do not add any padding, the size of the struct is three bytes. Then, if we make an array of these struct, the next struct s will begin three bytes from the start.
  • In that second struct s, the c member will be at an offset of three bytes. That violates the alignment requirement for short.
  • Therefore, to make this struct work, we must add one byte of padding. This makes the total size four bytes. Then, in an array of these struct, all the members will be at boundaries required by their alignment.

Even if you declare just a single object of a structure, as in struct s {short c; char a;} x;, a structure is always laid out so it can be used in an array.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
4

The first structure has one element of size 2 (assuming short has size 2 on your system). It is as good as directly having an array of short directly.

The second structure is a special thing: access to short variables is best done on even addresses. If we hadn't padding, we had the following:

struct s arr[5]; // an array
void * a = arr; // needed to reference it

Then,

  • arr[0].c is at a.
  • arr[0].a is at a + 2 bytes.
  • arr[1].c is at a + 3 bytes (!).
  • arr[1].a is at a + 5 bytes (!).

As it is preferrable to have arr[1].c at an even address, we add padding. Then,

  • arr[1].c is at a + 4 bytes.
  • arr[1].a is at a + 6 bytes.
glglgl
  • 89,107
  • 13
  • 149
  • 217