When do structures not have padding?
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 thestruct
. There is never any padding at the beginning.- If we make an array of these
struct
, the nextstruct s
will begin two bytes beyond the first, and its memberc
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 afterc
. This is fine, sincea
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 thesestruct
, the nextstruct s
will begin three bytes from the start. - In that second
struct s
, thec
member will be at an offset of three bytes. That violates the alignment requirement forshort
. - 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 thesestruct
, 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.
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 ata
.arr[0].a
is ata
+ 2 bytes.arr[1].c
is ata
+ 3 bytes (!).arr[1].a
is ata
+ 5 bytes (!).
As it is preferrable to have arr[1].c
at an even address, we add padding. Then,
arr[1].c
is ata
+ 4 bytes.arr[1].a
is ata
+ 6 bytes.