| |||
| Home > Coding Practices > Aligning data > The __packed qualifier and unaligned data access | |||
The __packed qualifier sets the alignment
of any valid type to one. This enables objects of packed type to
be read or written using unaligned accesses.
Examples of objects that can be packed include:
structures
unions
pointers.
See __packed in
the Compiler Reference Guide for more information
on the __packed qualifier.
For efficiency, fields in a structure are located on their natural size boundary. This means that the compiler often inserts padding between fields to ensure they are aligned.
When space is at a premium, the __packed qualifier
can be used to create structures without padding between fields.
Structures can be packed in two ways:
The entire struct can
be declared as __packed. For example:
__packed struct mystruct
{
char c;
short s;
} // not recommended
Each field of the structure inherits the __packed qualifier.
Declaring an entire struct as __packed typically
incurs a penalty both in code size and performance. See __packed structures versus individually
__packed fields.
Individual non-aligned fields within the struct can
be declared as __packed. For example:
struct mystruct
{
char c;
__packed short s; // recommended
}
This is the recommended approach to packing structures. See __packed structures versus individually __packed fields.
The same principles apply to unions. You can declare either
an entire union as __packed, or use the __packed attribute
to identify components of the union that are unaligned in memory.
Reading from and writing to structures qualified with __packed requires
unaligned accesses and can therefore incur a performance penalty.
See __packed structures versus individually
__packed fields.
By default, the ARM compiler expects conventional C pointers to point to an aligned word in memory, because this enables the compiler to generate more efficient code.
If you want to define a pointer that can point to a word at
any address, then you must specify this using the __packed qualifier
when defining the pointer. For example:
__packed int *pi; // pointer to unaligned int
When a pointer is declared as __packed,
the ARM compiler generates code that correctly accesses the dereferenced
value of the pointer, regardless of its alignment. The generated
code consists of a sequence of byte accesses, or variable alignment-dependent
shifting and masking instructions, rather than a simple LDR instruction.
Consequently, declaring a pointer as __packed incurs
a performance and code size penalty.
In some circumstances the compiler might intentionally generate
unaligned LDR instructions. In particular, the
compiler can do this to load halfwords from memory, even where the
architecture supports dedicated halfword load instructions.
For example, to access an unaligned short within
a __packed structure, the compiler might load
the required halfword into the top half of a register and then shift
it down to the bottom half. This operation requires only one memory
access, whereas performing the same operation using LDRB instructions
requires two memory accesses, plus instructions to merge the two
bytes.