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 may insert 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 may add some extra padding after the last data member. Consider the following example:
|
|
The GCC compiler always assumes that an instance of struct One
will start 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 figure below. Similarly, to align
data member c
, the compiler needs to insert three bytes
after c
.
In the case of struct One
, the compiler
will infer 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 will lay 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
GCC C/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.