Data Structure Alignment - Typical Alignment of C Structs On X86

Typical Alignment of C Structs On X86

Data structure members are stored sequentially in a memory so that in the structure below the member Data1 will always precede Data2 and Data2 will always precede Data3:

struct MyData { short Data1; short Data2; short Data3; };

If the type "short" is stored in two bytes of memory then each member of the data structure depicted above would be 2-byte aligned. Data1 would be at offset 0, Data2 at offset 2 and Data3 at offset 4. The size of this structure would be 6 bytes.

The type of each member of the structure usually has a default alignment, meaning that it will, unless otherwise requested by the programmer, be aligned on a pre-determined boundary. The following typical alignments are valid for compilers from Microsoft (Visual C++), Borland/CodeGear (C++Builder), Digital Mars (DMC) and GNU (GCC) when compiling for 32-bit x86:

  • A char (one byte) will be 1-byte aligned.
  • A short (two bytes) will be 2-byte aligned.
  • An int (four bytes) will be 4-byte aligned.
  • A long (four bytes) will be 4-byte aligned.
  • A float (four bytes) will be 4-byte aligned.
  • A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux (8-byte with -malign-double compile time option).
  • A long double (ten bytes with C++Builder and DMC, eight bytes with Visual C++, twelve bytes with GCC) will be 8-byte aligned with C++Builder, 2-byte aligned with DMC, 8-byte aligned with Visual C++ and 4-byte aligned with GCC.
  • Any pointer (four bytes) will be 4-byte aligned. (e.g.: char*, int*)

The only notable difference in alignment for a 64-bit system when compared to a 32-bit system is:

  • A long (eight bytes) will be 8-byte aligned.
  • A double (eight bytes) will be 8-byte aligned.
  • A long double (eight bytes with Visual C++, sixteen bytes with GCC) will be 8-byte aligned with Visual C++ and 16-byte aligned with GCC.
  • Any pointer (eight bytes) will be 8-byte aligned.

Here is a structure with members of various types, totaling 8 bytes before compilation:

struct MixedData { char Data1; short Data2; int Data3; char Data4; };

After compilation the data structure will be supplemented with padding bytes to ensure a proper alignment for each of its members:

struct MixedData /* After compilation in 32-bit x86 machine */ { char Data1; /* 1 byte */ char Padding1; /* 1 byte for the following 'short' to be aligned on a 2 byte boundary assuming that the address where structure begins is an even number */ short Data2; /* 2 bytes */ int Data3; /* 4 bytes - largest structure member */ char Data4; /* 1 byte */ char Padding2; /* 3 bytes to make total size of the structure 12 bytes */ };

The compiled size of the structure is now 12 bytes. It is important to note that the last member is padded with the number of bytes required so that the total size of the structure should be a multiple of the largest alignment of any structure member (alignment(int) in this case, which = 4 on linux-32bit/gcc). from February 2011">citation needed]]]. In this case 3 bytes are added to the last member to pad the structure to the size of a 12 bytes (alignment(int) × 3).

struct FinalPad { double x; char n; };

In this example the total size of the structure sizeof(FinalPad) = 8 not 5 (so that the size is a multiple of 4 (alignment(double) = 4 on linux-32bit/gcc)) (Note: This is likely a mistake in the explanation. The total size of the structure sizeof(FinalPad) = 12 on linux-32bit/gcc. It can be 8 if "float x" is used.).

struct FinalPadShort { short s; char n; };

In this example the total size of the structure sizeof(FinalPadShort) = 6 not 5 (not 8 either) (so that the size is a multiple of 2 (alignment(short) = 2 on linux-32bit/gcc)).

It is possible to change the alignment of structures to reduce the memory they require (or to conform to an existing format) by reordering structure members or changing the compiler’s alignment (or “packing”) of structure members.

struct MixedData /* after reordering */ { char Data1; char Data4; /* reordered */ short Data2; int Data3; };

The compiled size of the structure now matches the pre-compiled size of 8 bytes. Note that Padding1 has been replaced (and thus eliminated) by Data4 and Padding2 is no longer necessary as the structure is already aligned to the size of a long word.

The alternative method of enforcing the MixedData structure to be aligned to a one byte boundary will cause the pre-processor to discard the pre-determined alignment of the structure members and thus no padding bytes would be inserted.

While there is no standard way of defining the alignment of structure members, some compilers use #pragma directives to specify packing inside source files. Here is an example:

#pragma pack(push) /* push current alignment to stack */ #pragma pack(1) /* set alignment to 1 byte boundary */ struct MyPackedData { char Data1; long Data2; char Data3; }; #pragma pack(pop) /* restore original alignment from stack */

This structure would have a compiled size of 6 bytes on a 32-bit system. The above directives are available in compilers from Microsoft, Borland, GNU and many others.

Another example:

struct MyPackedData { char Data1; long Data2 __attribute__((packed)); char Data3; };

Read more about this topic:  Data Structure Alignment

Famous quotes containing the word typical:

    Compare the history of the novel to that of rock ‘n’ roll. Both started out a minority taste, became a mass taste, and then splintered into several subgenres. Both have been the typical cultural expressions of classes and epochs. Both started out aggressively fighting for their share of attention, novels attacking the drama, the tract, and the poem, rock attacking jazz and pop and rolling over classical music.
    W. T. Lhamon, U.S. educator, critic. “Material Differences,” Deliberate Speed: The Origins of a Cultural Style in the American 1950s, Smithsonian (1990)