Here's what C and C++ compilers must do to keep structure members aligned.
Padding and sizeof
For any type T, an object of type "pointer to T" can point to any T object, whether that object is an individual object, a structure member, or an array element. For example, given:
widget w;
widget x[10];
widget *p = &w;
widget *q = &x[2];
the assignment:
*q = *p;
copies the value of a standalone widget object into a widget that's an array element. For such assignments to work, all widget objects must have the same size and alignment.
The size of each structure must be a multiple of its alignment. Compilers add trailing padding to each structure if necessary to make this so. For example, since widget must be word aligned, the compiler adds trailing padding to bring the size of a widget up to the next multiple of the word size, which in my examples, is four.
The sizeof operator applied to a structure such as widget yields the total number of bytes in the object, including any padding. In the case of widget compiled for a target processor where sizeof(int) equals four, the cumulative size of widget's three members would be six:
sizeof(char) +
sizeof(int) + sizeof(char) = 6
However, the padding adds six more bytes, so for our hypothetical target processor, sizeof(widget) would be 12. Type widget has an alignment of four, and 12 is a multiple of four.
Why must the size of a structure be a multiple of its alignment? Well, suppose it weren't. Suppose that widget had no trailing padding so that sizeof(widget) were nine. However, each element in an array of widgets would still have to be word aligned, so each array element would have to be padded with three bytes. That padding just wouldn't be counted in the size of each element. What's wrong with that?
According to both the C and C++ Standards, "When applied to an array, the result [of the sizeof operator] is the total number of bytes in the array."2,4 The C++ Standard adds that "This implies that the size of an array of n elements is n times the size of an element." If the padding after each array weren't counted in the size of each element, then the size of an array of n elements would in fact be greater than n times the size of each element. Various common programming techniques would cease to work.
For example, the common C idiom for allocating storage for an array of n widgets is to call malloc in an expression of the form:
pw = malloc(n * sizeof(widget));
If sizeof(widget) didn't account for the trailing padding after each widget, then this expressions could easily allocate too little storage for the entire array.