Export (0) Print
Expand All

Avoiding Alignment Errors

9/7/2007

All data types are either primitive types, or complex types that consist of arrays, structures, or unions of simpler types.

In general, alignment errors can be avoided by following these rules:

  • Do not enable structure packing.
  • Do not access a small-aligned address by using a recast pointer of larger alignment.

For example, treating the address of a char data type as a pointer to a long can cause an alignment error because this might mean executing a four-byte move from an address that is not a multiple of four.

The following example illustrates this style of coding:

char a[10];
char *p = &a[1];
long l = *(long *)p;   // ERROR!; Attempt to move a long from
                       // the address of a char.

Accessing a large-aligned address with a recast pointer of smaller alignment is safe. For example, you could use a char * cast to access the first byte, or any byte, of a long variable.

If you need to pack structures or move data to unaligned addresses, use the __unaligned keyword.

This keyword cannot resolve alignment problems of pre-existing classes such as in inherited code, or in the Microsoft Foundation Class Library.

You might need to use structure packing in programs that use large arrays of structures, or to read a pre-existing data format.

In such cases, you can still use packed structures if you also carefully unpack members of a packed structure before using data in the program. This technique might involve copying the data in a structure member-by-member, or element-by-element, or field-by-field, into a temporary location that is correctly aligned.

Syntactically, __unaligned is a type qualifier like const and volatile; it controls the meaning of what the pointer points to. __unaligned has meaning only when used in a pointer declaration.

The following code example shows the use of __unaligned pointer declarations:

int __unaligned *p1;             // p1 is a pointer to unaligned int
struct {int i;} __unaligned *p2; // p2 is a pointer to unaligned struct

The following code example illustrates the correct and incorrect use of __unaligned and #pragma pack in conjunction with integer operations. In the first section, a fault is generated because the __unaligned qualifier is not used, whereas in the second section, the __unaligned qualifier is used correctly.

#pragma pack (1)
struct s {
   char c;            // offset 0
   int i;             // offset 1!
} ss;
#pragma pack ()
 
void f_improper(int *p)
{
   *p = 23;        // generates a fault
}
 
void g_proper(int __unaligned *p)   // OK
{
   *p = 42;
}
 
void main ()
{
   f_improper(&ss.i);
   g_proper(&ss.i);
}

The output from this example appears in the following machine code example. In the output, function f_improper shows the code generated by the improper handling of unaligned data, and function g_proper shows the extra code generated when __unaligned is used.

In function g_proper, more than double the number of instructions are generated to handle the unaligned data, but an alignment fault cannot occur.

f_improper::
   mov r3, #0x17
   str r0, [r0]      // This instruction gets an alignment fault.
   mov pc, lr
 
g_proper::
   mov r3, #0x2A
   strb r3, [r0]     // Four individual bytes are stored,
   mov r3, #0        // avoiding an alignment fault.
   strb r3, [r0, #1]    
   strb r3, [r0, #2]    
   strb r3, [r0, #2]  
   mov  pc, lr

Because there is a performance penalty for accessing data through an __unaligned pointer, use the __unaligned keyword only when needed.

To guarantee that there are no alignment errors, the compiler must access the de-referenced data as a series of smaller pieces.

If the data is already aligned, this technique for accessing data is not necessary.

The following list summarizes the rules for alignment of complex types:

  • The alignment of an array is the same as the alignment of the base type.
  • The alignment of a structure or object is the maximum of the alignment factors of all members of the structure. Further, as long as structure packing is turned off, the compiler pads the structure so each member is placed at the next available properly aligned address for that member.

The alignment of a union is also the maximum of the alignment factors of all members. Each member's address is that of the union itself, so there is no padding.

Show:
© 2014 Microsoft