As shown in the table in Data Alignment, the native data types have a well-defined alignment structure but what about user-defined data types? The C++ compiler also needs to make sure that all the member variables in a struct or class are properly aligned. For this, the compiler inserts padding bytes between member variables. In addition, to make sure that each element in an array of a user-defined type is aligned, the compiler can add some extra padding after the last data member. Consider the following example:
|
|
The compiler always assumes that an instance of struct
One starts at an address aligned to the most strict alignment requirement
of all of the struct's members, which is int in this
case. This is actually how the alignment requirements of user-defined types are
calculated. Assuming the memory are on x86-64 alignment with short int having the alignment of 2 and int having an alignment of 4, to make the i data member of struct One suitably
aligned, the compiler needs to insert two extra bytes of padding between s and i to create
alignment, as shown in the following figure. Similarly, to align data member c, the compiler needs to insert three bytes after c.
In the case of struct One, the compiler infers
a total size of 12 bytes based on the arrangement of the elements of the struct.
However, if the elements of the struct are reordered (as shown in struct Two), the compiler is now able to infer the smaller
size of 8 bytes.
By default, the C/C++ compiler lays out members of a struct in the order in
which they are declared, with possible padding bytes inserted between members, or after
the last member, to ensure that each member is aligned properly. However, the C++
compiler provides a language extension, __attribute__((packed))which tells the compiler not to insert padding but
rather allow the struct members to be misaligned. For example, if the system normally
requires all int objects to have 4-byte alignment, the
usage of __attribute__((packed)) can cause int struct members to be allocated at odd offsets.
Usage of __attribute__((packed)) must be
carefully considered because accessing unaligned memory can cause the compiler to insert
code to read the memory byte by byte instead of reading multiple chunks of memory at one
time.