GNAT requires that all alignment clauses specify a power of 2, and all default alignments are always a power of 2. The default alignment values are as follows:
For elementary types, the alignment is the minimum of the actual size of objects of the type divided by Storage_Unit, and the maximum alignment supported by the target. (This maximum alignment is given by the GNAT-specific attribute Standard'Maximum_Alignment; see Attribute Maximum_Alignment.)
For example, for type Long_Float, the object size is 8 bytes, and the default alignment will be 8 on any target that supports alignments this large, but on some targets, the maximum alignment may be smaller than 8, in which case objects of type Long_Float will be maximally aligned.
For arrays, the alignment is equal to the alignment of the component type for the normal case where no packing or component size is given. If the array is packed, and the packing is effective (see separate section on packed arrays), then the alignment will be either 4, 2, or 1 for long packed arrays or arrays whose length is not known at compile time, depending on whether the component size is divisible by 4, 2, or is odd. For short packed arrays, which are handled internally as modular types, the alignment will be as described for elementary types, e.g. a packed array of length 31 bits will have an object size of four bytes, and an alignment of 4.
For the normal non-packed case, the alignment of a record is equal to the maximum alignment of any of its components. For tagged records, this includes the implicit access type used for the tag. If a pragma Pack is used and all components are packable (see separate section on pragma Pack), then the resulting alignment is 1, unless the layout of the record makes it profitable to increase it.
A special case is when:
In this case, an alignment is chosen to match the size of the record. For example, if we have:
type Small is record A, B : Character; end record; for Small'Size use 16;
then the default alignment of the record type Small is 2, not 1. This leads to more efficient code when the record is treated as a unit, and also allows the type to specified as Atomic on architectures requiring strict alignment.
An alignment clause may specify a larger alignment than the default value up to some maximum value dependent on the target (obtainable by using the attribute reference Standard'Maximum_Alignment). It may also specify a smaller alignment than the default value for enumeration, integer and fixed point types, as well as for record types, for example
type V is record A : Integer; end record; for V'alignment use 1;
The default alignment for the type V is 4, as a result of the Integer field in the record, but it is permissible, as shown, to override the default alignment of the record with a smaller value.
Note that according to the Ada standard, an alignment clause applies only to the first named subtype. If additional subtypes are declared, then the compiler is allowed to choose any alignment it likes, and there is no way to control this choice. Consider:
type R is range 1 .. 10_000; for R'Alignment use 1; subtype RS is R range 1 .. 1000;
The alignment clause specifies an alignment of 1 for the first named subtype R but this does not necessarily apply to RS. When writing portable Ada code, you should avoid writing code that explicitly or implicitly relies on the alignment of such subtypes.
For the GNAT compiler, if an explicit alignment clause is given, this value is also used for any subsequent subtypes. So for GNAT, in the above example, you can count on the alignment of RS being 1. But this assumption is non-portable, and other compilers may choose different alignments for the subtype RS.