124 3. Fundamentals of Software Engineering for Games
or class, the compiler introduces padding (holes) in order to ensure that every-
thing is properly aligned. It’s a good idea to think about alignment and pack-
ing when declaring your data structures. By simply rearranging the members
of struct InefficientPacking from the example above, we can eliminate
some of the wasted padding space, as shown below and in Figure 3.15:
struct MoreEfficientPacking
{
U32 mU1; // 32 bits (4-byte aligned)
F32 mF2; // 32 bits (4-byte aligned)
I32 mI4; // 32 bits (4-byte aligned)
char* mP6; // 32 bits (4-byte aligned)
U8 mB3; // 8 bits (1-byte aligned)
bool mB5; // 8 bits (1-byte aligned)
};
You’ll notice in Figure 3.15 that the size of the structure as a whole is
now 20 bytes, not 18 bytes as we might expect, because it has been padded
by two bytes at the end. This padding is added by the compiler to ensure
proper alignment of the structure in an array context. That is, if an array of
these structs is defi ned and the fi rst element of the array is aligned, then the
padding at the end guarantees that all subsequent elements will also be aligned
properly.
The alignment of a structure as a whole is equal to the largest alignment
requirement among its members. In the example above, the largest mem-
ber alignment is four-byte, so the structure as a whole should be four-byte
CPU
alignedValue
0x6A341170
0x6A341174
0x6A341178
register
-alignedValue
0x6A341170
0x6A341174
0x6A341178
un-
-alignedValue
shift un-
shift
un- -alignedValue
Aligned read from
0x6A341174
Unaligned read from
0x6A341173
CPU
register
Figure 3.14. Aligned and unaligned reads of a 32-bit integer.
(pad)
mU1
mF2
mB3
mI4
mB5
mP6
+0x0
+0x4
+0x8
+0xC
+0x10
Figure 3.15. More ef-
fi cient packing by
grouping small mem-
bers together.