Channels ▼


Padding and Rearranging Structure Members

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." 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.
As another example, suppose that gadget is a structure defined as:

struct gadget
    char m1;
    double m2;
    char m3;

and that objects of type double must be double-word aligned. The compiler will add 7 bytes of padding after member m1 and also after member m3, as if the structure had been defined as:

struct gadget
    char m1;
    char padding_after_m1[7];
    double m2;
    char m3;
    char padding_after_m3[7];

The most strictly aligned member of gadget is m2, which is double-word aligned. Thus, each gadget must also be double-word aligned. The padding after m1 ensures that member m2 is double-word aligned relative to the beginning of each gadget. The padding after m3 ensures that the next gadget in an array of gadgets is also double-word aligned.

Rearranging Members to Reduce Padding

You can reduce the size of each widget by rearranging the members to reduce the number of padding bytes. Specifically, you can rearrange the member declarations so that the char members m1 and m3 are adjacent to each other, as in:

struct widget
    char m1;
    char m3;
    int m2;

In this case, the compiler will add only two padding bytes, as if you had declared widget as:

struct widget
    char m1;
    char m3;
    char padding[2];
    int m2;

Consequently, sizeof(widget) would be only eight, rather than 12. (Again, I'm calculating these sizes assuming an int is a 4-byte object aligned to an address that's a multiple of four. The sizes could be different on a machine with different object sizes and alignment requirements.)

You can rearrange widget's members in other ways to reduce the number of padding bytes. For example, defining widget as:

struct widget
    int m2;
    char m1;
    char m3;

also reduces the number of padding bytes to two and sizeof(widget) to eight.

A Standard C compiler won't rearrange the members of a structure automatically to reduce the structure's size. According to the Standard: "Within a structure object, the non-bit-field members … have addresses that increase in the order in which they are declared." This effectively prohibits compilers from rearranging structure members from the order in which they're declared.

Class Padding in C++

A C++ class is a generalization of a C structure. For the most part, C code that defines and uses structures behaves the same when compiled and executed as C++.

A C++ class can have elements that a C structure cannot, such as access specifiers (public, protected, and private), member functions, static data members, and base classes. Some of these elements alter the physical layout of class objects and complicate the rules for padding. Those rules will be the subject of a future article.


Thanks to Joel Saks for all his help.


Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags


<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags


<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

