Data alignment

From cppreference.com
< c‎ | language

Complete object types have alignment requirements which place restrictions on the addresses at which objects of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type: stricter alignment can be requested using the _Alignas keyword.

A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported by the implementation in all contexts, which is equal to _Alignof (max_align_t).

An extended alignment is represented by an alignment greater than _Alignof (max_align_t). It is implementation-defined whether any extended alignments are supported and the contexts in which they are supported. A type having an extended alignment requirement is an over-aligned type.

Alignments are represented as values of the type size_t. Valid alignments include only those values returned by an _Alignof expression for fundamental types, plus an additional implementation-defined set of values, which may be empty. Every valid alignment value shall be a nonnegative integral power of two.

Alignments have an order from weaker to stronger or stricter alignments. Stricter alignments have larger alignment values. An address that satisfies an alignment requirement also satisfies any weaker valid alignment requirement.

The alignment requirement of a complete type can be queried using an _Alignof expression. The types char, signed char, and unsigned char shall have the weakest alignment requirement.

Comparing alignments is meaningful and provides the obvious results:

  • Two alignments are equal when their numeric values are equal.
  • Two alignments are different when their numeric values are not equal.
  • When an alignment is larger than another it represents a stricter alignment.

[edit] Notes

Every data type in C has an alignment requirement which the architecture of the processor mandates. The word length of a processor is the same as the data bus size. Consider a variable with type double and the size of type double being eight bytes. On a 32-bit machine, the processing word size (and the bus size) is four bytes; a double variable allocated on an 8-byte boundary requires only two memory read cycles. On a 64-bit machine, the processing word size (and the bus size) is eight bytes; a double variable allocated on an 8-byte boundary requires only one memory read cycle. A double variable not aligned on an 8-byte boundary requires more read cycles plus some effort to combine the pieces leading to lower performance.

[edit] Example

Alignments are integral powers of two.

#include <stdio.h>
#include <stddef.h>
 
int main(void)
{
    printf("%2zu\n", _Alignof(unsigned char));
    printf("%2zu\n", _Alignof(int));
    printf("%2zu\n", _Alignof(double));
    printf("%2zu\n", _Alignof(long double));
    printf("%2zu\n", _Alignof(long double _Complex));
    printf("%2zu\n", _Alignof(max_align_t));
 
    /* The compiler inserts padding bytes between members and after the last member */
    /* to ensure that all members are aligned properly in an array of the struct.   */
    struct s {
        char c;
        /* 7 bytes of padding here */
        double d;   /* greatest alignment requirement is alignment of struct */
        int i;
        /* 4 bytes of padding here */
    } ss[2];
    printf("sizeof(s)   = %2zu\n", sizeof(struct s));
    printf("_Alignof(s) = %2zu\n", _Alignof(struct s));
    printf("&ss[0].d    = %p\n", (void*)&ss[0].d);   /* 8-byte alignment */
    printf("&ss[1].d    = %p\n", (void*)&ss[1].d);
 
    /* Make an alignment stricter. */
    int a;
    printf("&a          = %p\n", (void*)&a);   /* 4-byte alignment  */
    _Alignas(16) int b;
    printf("&b          = %p\n", (void*)&b);   /* 16-byte alignment */
 
    return 0;
}

Possible output:

1
 4
 8
16
16
16
sizeof(s)   = 24
_Alignof(s) =  8
&ss[0].d    = 0x7fffaef5a468
&ss[1].d    = 0x7fffaef5a480
&a          = 0x7fffaef5a45c
&b          = 0x7fffaef5a450