13.5 Record Layout
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
The (record) layout aspect of representation consists of the storage places for some or all components, that is, storage place attributes of the components. The layout can be specified with a record_representation_clause
.
13.5.1 Record Representation Clauses
1[A record_representation_clause
specifies the storage representation of records and record extensions, that is, the order, position, and size of components (including discriminants, if any). ]
Language Design Principles
record_representation_clause
s. Syntax
2/5record_representation_clause
::=
for first_subtype_local_name
use
record [mod_clause
]
{component_clause
}
end record [local_name
];
3component_clause
::=
component_local_name
at position
range first_bit
.. last_bit
;
4position
::=
static_expression
5first_bit
::=
static_simple_expression
6last_bit
::=
static_simple_expression
First_bit
and last_bit
need to be simple_expression
instead of expression
for the same reason as in range
(see 3.5, “Scalar Types”). If a local_name
appears at the end of the record_representation_clause
, it shall repeat the first_subtype_local_name
.
Name Resolution Rules
7Each position
, first_bit
, and last_bit
is expected to be of any integer type.
Legality Rules
8/2The first_subtype_local_name
of a record_representation_clause
shall denote a specific record or record extension subtype.
local_name
is required to denote a first subtype. If the component_local_name
is a direct_name
, the local_name
shall denote a component of the type. For a record extension, the component shall not be inherited, and shall not be a discriminant that corresponds to a discriminant of the parent type. If the component_local_name
has an attribute_designator
, the direct_name
of the local_name
shall denote either the declaration of the type or a component of the type, and the attribute_designator
shall denote an implementation-defined implicit component of the type.
The position
, first_bit
, and last_bit
shall be static expressions. The value of position
and first_bit
shall be nonnegative. The value of last_bit
shall be no less than first_bit
– 1.
component_clause
such as “X at 4 range 0..–1;” is allowed if X can fit in zero bits. If the nondefault bit ordering applies to the type, then either:
- the value of
last_bit
shall be less than the size of the largest machine scalar; or 10.3/2 - the value of
first_bit
shall be zero and the value oflast_bit
+ 1 shall be a multiple of System.Storage_Unit.
At most one component_clause
is allowed for each component of the type, including for each discriminant (component_clause
s may be given for some, all, or none of the components). Storage places within a component_list
shall not overlap, unless they are for components in distinct variant
s of the same variant_part
.
A name that denotes a component of a type is not allowed within a record_representation_clause
for the type, except as the component_local_name
of a component_clause
.
record_representation_clause
part of the declarative region, and then disallow mentions of the components within almost all of the record_representation_clause
. The alternative would be to treat the component_local_name
like a formal parameter name in a subprogram call (in terms of visibility). However, this rule would imply slightly different semantics, because (given the actual rule) the components can hide other declarations. This was the rule in Ada 83, and we see no reason to change it. The following, for example, was and is illegal: type T is
record
X : Integer;
end record;
X : constant := 31; -- Same defining name as the component.
for T use
record
X at 0 range 0..X; -- Illegal!
end record;
record_representation_clause
. Static Semantics
13/2A record_representation_clause
(without the mod_clause
) specifies the layout.
record_representation_clause
, not by an aspect_specification
.If the default bit ordering applies to the type, the position
, first_bit
, and last_bit
of each component_clause
directly specify the position and size of the corresponding component.
If the nondefault bit ordering applies to the type, then the layout is determined as follows:
- the
component_clause
s for which the value oflast_bit
is greater than or equal to the size of the largest machine scalar directly specify the position and size of the corresponding component; 13.4/2 - for other
component_clause
s, all of the components having the same value ofposition
are considered to be part of a single machine scalar, located at thatposition
; this machine scalar has a size which is the smallest machine scalar size larger than the largestlast_bit
for allcomponent_clause
s at thatposition
; thefirst_bit
andlast_bit
of eachcomponent_clause
are then interpreted as bit offsets in this machine scalar.
component_clause
also determines the value of the Size attribute of the component, since this attribute is related to First_Bit and Last_Bit. [A record_representation_clause
for a record extension does not override the layout of the parent part;] if the layout was specified for the parent type, it is inherited by the record extension.
Implementation Permissions
15An implementation may generate implementation-defined components (for example, one containing the offset of another component). An implementation may generate names that denote such implementation-defined components; such names shall be implementation-defined attribute_reference
s. An implementation may allow such implementation-defined names to be used in record_representation_clause
s. An implementation can restrict such component_clause
s in any manner it sees fit.
component_clause
s, for example. The visibility rules for such names are up to the implementation.If a record_representation_clause
is given for an untagged derived type, the storage place attributes for all of the components of the derived type may differ from those of the corresponding components of the parent type, even for components whose storage place is not specified explicitly in the record_representation_clause
.
Implementation Advice
17The recommended level of support for record_representation_clause
s is:
- An implementation should support machine scalars that correspond to all of the integer, floating point, and address formats supported by the machine.
- An implementation should support storage places that can be extracted with a load, mask, shift sequence of machine code, and set with a load, shift, mask, store sequence, given the available machine instructions and run-time model.
- A storage place should be supported if its size is equal to the Size of the component subtype, and it starts and ends on a boundary that obeys the Alignment of the component subtype.
- For a component with a subtype whose Size is less than the word size, any storage place that does not cross an aligned word boundary should be supported.
- An implementation may reserve a storage place for the tag field of a tagged type, and disallow other components from overlapping that place.
- An implementation is not required to support a
component_clause
for a component of an extension part if the storage place is not after the storage places of all components of the parent type, whether or not those storage places had been specified.
record_representation_clause
s should be followed.component_clause
is given for a component, then the choice of the storage place for the component is left to the implementation. If component_clause
s are given for all components, the record_representation_clause
completely specifies the representation of the type and will be obeyed exactly by the implementation. record_representation_clause
at any place except for the component_local_name
of a component_clause
. However, since the record_representation_clause
is part of the declarative region of the type declaration, the component names hide outer homographs throughout.record_representation_clause
cannot be given for a protected type, even though protected types, like record types, have components. The primary reason for this rule is that there is likely to be too much dope in a protected type — entry queues, bit maps for barrier values, etc. In order to control the representation of the user-defined components, simply declare a record type, give it a record_representation_clause
, and give the protected type one component whose type is the record type. Alternatively, if the protected object is protecting something like a device register, it makes more sense to keep the thing being protected outside the protected object (possibly with a pointer to it in the protected object), in order to keep implementation-defined components out of the way. Examples
24Example of specifying the layout of a record type:
Word : constant := 4; -- storage element is byte, 4 bytes per word
26type State is (A,M,W,P);
type Mode is (Fix, Dec, Exp, Signif);
27/5type Byte_Mask is array (0..7) of Boolean with Component_Size => 1;
type State_Mask is array (State) of Boolean with Component_Size => 1;
type Mode_Mask is array (Mode) of Boolean with Component_Size => 1;
28type Program_Status_Word is
record
System_Mask : Byte_Mask;
Protection_Key : Integer range 0 .. 3;
Machine_State : State_Mask;
Interrupt_Cause : Interruption_Code;
Ilc : Integer range 0 .. 3;
Cc : Integer range 0 .. 3;
Program_Mask : Mode_Mask;
Inst_Address : Address;
end record;
29for Program_Status_Word use
record
System_Mask at 0*Word range 0 .. 7;
Protection_Key at 0*Word range 10 .. 11; -- bits 8,9 unused
Machine_State at 0*Word range 12 .. 15;
Interrupt_Cause at 0*Word range 16 .. 31;
Ilc at 1*Word range 0 .. 1; -- second word
Cc at 1*Word range 2 .. 3;
Program_Mask at 1*Word range 4 .. 7;
Inst_Address at 1*Word range 8 .. 31;
end record;
30for Program_Status_Word'Size use 8*System.Storage_Unit;
for Program_Status_Word'Alignment use 8;
31/5The record_representation_clause
defines the record layout. The Size clause guarantees that (at least) eight storage elements are used for objects of the type. The Alignment clause guarantees that aliased, imported, or exported objects of the type will have addresses divisible by eight.
Wording Changes from Ada 83
attribute_reference
of a component or of the first subtype itself; surely Ada 83 did not intend to allow arbitrary identifiers.Incompatibilities With Ada 95
record_representation_clause
for the nondefault bit order is now clearly defined. Thus, such clauses can be portably written. In order to do that though, the equivalence of bit 1 in word 1 to bit 9 in word 0 (for a machine with Storage_Unit = 8) had to be dropped for the nondefault bit order. Any record_representation_clause
s which depends on that equivalence will break (although such code would imply a noncontiguous representation for a component, and it seems unlikely that compilers were supporting that anyway). Extensions to Ada 95
record_representation_clause
s on limited record types is removed. Extensions to Ada 2012
13.5.2 Storage Place Attributes
Static Semantics
1For a component C of a composite, non-array object R, the storage place attributes are defined:
record_representation_clause
. R.C'Position
- If the nondefault bit ordering applies to the composite type, and if a
component_clause
specifies the placement of C, denotes the value given for theposition
of thecomponent_clause
; otherwise, denotes the same value as R.C'Address – R'Address. The value of this attribute is of the type universal_integer.
R.C'First_Bit
- If the nondefault bit ordering applies to the composite type, and if a
component_clause
specifies the placement of C, denotes the value given for thefirst_bit
of thecomponent_clause
; otherwise, denotes the offset, from the start of the first of the storage elements occupied by C, of the first bit occupied by C. This offset is measured in bits. The first bit of a storage element is numbered zero. The value of this attribute is of the type universal_integer. 4/2
R.C'Last_Bit- If the nondefault bit ordering applies to the composite type, and if a
component_clause
specifies the placement of C, denotes the value given for thelast_bit
of thecomponent_clause
; otherwise, denotes the offset, from the start of the first of the storage elements occupied by C, of the last bit occupied by C. This offset is measured in bits. The value of this attribute is of the type universal_integer.
component_clause
applies to a component, then that component will be at the same relative storage place in all objects of the type. Otherwise, there is no such requirement. Implementation Advice
5If a component is represented using some form of pointer (such as an offset) to the actual data of the component, and this data is contiguous with the rest of the object, then the storage place attributes should reflect the place of the actual data, not the pointer. If a component is allocated discontiguously from the rest of the object, then a warning should be generated upon reference to one of its storage place attributes.
component_clause
for that component. Incompatibilities With Ada 95
13.5.3 Bit Ordering
1[The Bit_Order attribute specifies the interpretation of the storage place attributes.]
attribute_definition_clause
can be used to force all implementations to use the same bit ordering. Static Semantics
2A bit ordering is a method of interpreting the meaning of the storage place attributes. High_Order_First [(known in the vernacular as “big endian”)] means that the first bit of a storage element (bit 0) is the most significant bit (interpreting the sequence of bits that represent a component as an unsigned integer value). Low_Order_First [(known in the vernacular as “little endian”)] means the opposite: the first bit is the least significant.
For every specific record subtype S, the following representation attribute is defined:
S'Bit_Order
- Denotes the bit ordering for the type of S. The value of this attribute is of type System.Bit_Order. Bit_Order may be specified for specific record types via an
attribute_definition_clause
; the expression of such a clause shall be static.
record_representation_clause
.If Word_Size = Storage_Unit, the default bit ordering is implementation defined. If Word_Size > Storage_Unit, the default bit ordering is the same as the ordering of storage elements in a word, when interpreted as an integer.
The storage place attributes of a component of a type are interpreted according to the bit ordering of the type.
position
, first_bit
, and last_bit
of a component_clause
of a record_representation_clause
obey the bit ordering given in a representation item. Implementation Advice
7The recommended level of support for the nondefault bit ordering is:
- The implementation should support the nondefault bit ordering in addition to the default bit ordering.
record_representation_clause
s that can be ported between machines having different bit ordering. They do not guarantee transparent exchange of data between such machines.