GNAT requires that all alignment clauses specify 0 or a power of 2, and all default alignments are always a power of 2. Specifying 0 is the same as specifying 1.
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 unpacked 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
.