Contents Index Previous Next
13.3 Operational and Representation AttributesRepresentation Attributes
1/1
{
8652/0009}
[
{representation attribute} {attribute
(representation)} The values of certain implementation-dependent
characteristics can be obtained by interrogating appropriate
operational
or representation attributes.
{attribute (specifying)
[distributed]} Some of these attributes are specifiable
via an
attribute_definition_clause.]
Language Design Principles
1.a
In general, the meaning of a given
attribute should not depend on whether the attribute was specified via
an attribute_definition_clause,
or chosen by default by the implementation.
Syntax
2
attribute_definition_clause
::=
for local_name'
attribute_designator use expression;
|
for local_name'
attribute_designator use name;
Name Resolution Rules
3
For an attribute_definition_clause
that specifies an attribute that denotes a value, the form with an expression
shall be used. Otherwise, the form with a name
shall be used.
4
{expected type (attribute_definition_clause
expression or name) [partial]} For an
attribute_definition_clause that
specifies an attribute that denotes a value or an object, the expected
type for the expression or
name
is that of the attribute.
{expected profile (attribute_definition_clause
name) [partial]} For an
attribute_definition_clause
that specifies an attribute that denotes a subprogram, the expected profile
for the
name is the profile required
for the attribute. For an
attribute_definition_clause
that specifies an attribute that denotes some other kind of entity, the
name shall resolve to denote an
entity of the appropriate kind.
4.a
Ramification: For example,
the Size attribute is of type universal_integer. Therefore, the
expected type for Y in ``for X'Size use Y;'' is universal_integer,
which means that Y can be of any integer type.
4.b
Discussion: For attributes
that denote subprograms, the required profile is indicated separately
for the individual attributes.
4.c
Ramification:
For an attribute_definition_clause
with a name, the name
need not statically denote the entity it denotes. For example, the following
kinds of things are allowed:
4.d
for Some_Access_Type'Storage_Pool use Storage_Pool_Array(I);
for Some_Type'Read use Subprogram_Pointer.all;
Legality Rules
5/1
{
8652/0009}
{specifiable (of an attribute and for an entity) [distributed]}
{attribute (specifiable) [distributed]}
An
attribute_designator
is allowed in an
attribute_definition_clause
only if this International Standard explicitly allows it, or for an implementation-defined
attribute if the implementation allows it.
{aspect of representation
(specifiable attributes) [partial]} Each specifiable
attribute constitutes an
{operational aspect (specifiable
attributes) [partial]} operational aspect or
aspect of representation.
5.a
Discussion: For each specifiable
attribute, we generally say something like, ``The ... attribute may be
specified for ... via an attribute_definition_clause.''
5.b
The above wording allows for T'Class'Alignment,
T'Class'Size, T'Class'Input, and T'Class'Output to be specifiable.
5.c
A specifiable attribute is not
necessarily specifiable for all entities for which it is defined. For
example, one is allowed to ask T'Component_Size for an array subtype
T, but ``for T'Component_Size use ...'' is only allowed
if T is a first subtype, because Component_Size is a type-related aspect.
6
For an
attribute_definition_clause
that specifies an attribute that denotes a subprogram, the profile shall
be mode conformant with the one required for the attribute, and the convention
shall be Ada. Additional requirements are defined for particular attributes.
{subtype conformance (required)}
6.a
Ramification:
This implies, for example, that if one writes:
6.b
for T'Read use R;
6.c
R has to be a procedure with two parameters
with the appropriate subtypes and modes as shown in 13.13.2.
Static Semantics
7
{Address clause} {Alignment
clause} {Size clause}
{Component_Size clause}
{External_Tag clause}
{Small clause} {Bit_Order
clause} {Storage_Pool
clause} {Storage_Size
clause} {Read clause}
{Write clause} {Input
clause} {Output clause}
{Machine_Radix clause}
A
Size clause is an
attribute_definition_clause
whose
attribute_designator is Size.
Similar definitions apply to the other specifiable attributes.
7.a
To be honest: {type-related
(attribute_definition_clause) [partial]} {subtype-specific
(attribute_definition_clause) [partial]} An attribute_definition_clause
is type-related or subtype-specific if the attribute_designator
denotes a type-related or subtype-specific attribute, respectively.
8
{storage element}
{byte: See storage element}
A
storage element is an addressable element
of storage in the machine.
{word} A
word is the largest amount of storage that can be conveniently
and efficiently manipulated by the hardware, given the implementation's
run-time model. A word consists of an integral number of storage elements.
8.a
Discussion: A storage element
is not intended to be a single bit, unless the machine can efficiently
address individual bits.
8.b
Ramification: For example,
on a machine with 8-bit storage elements, if there exist 32-bit integer
registers, with a full set of arithmetic and logical instructions to
manipulate those registers, a word ought to be 4 storage elements --
that is, 32 bits.
8.c
Discussion: The ``given
the implementation's run-time model'' part is intended to imply that,
for example, on an 80386 running MS-DOS, the word might be 16 bits, even
though the hardware can support 32 bits.
8.d
A word is what ACID refers to
as a ``natural hardware boundary''.
8.e
Storage elements may, but need not be,
independently addressable (see 9.10, ``Shared
Variables''). Words are expected to be independently addressable.
9/1
{
8652/0009}
The following representation attributes are defined: Address, Alignment,
Size, Storage_Size, and Component_Size.The following attributes are defined:
10/1
For a prefixprefix
X that denotes an object, program unit, or label:
11
- X'Address
-
Denotes the address of the first
of the storage elements allocated to X. For a program unit or label,
this value refers to the machine code associated with the corresponding
body or statement. The value of
this attribute is of type System.Address.
11.a
Ramification: Here, the
``first of the storage elements'' is intended to mean the one with the
lowest address; the endianness of the machine doesn't matter.
12
- {specifiable (of Address for stand-alone
objects and for program units) [partial]} {Address
clause} Address may be specified for stand-alone
objects and for program units via an attribute_definition_clause.
12.a
Ramification: Address is
not allowed for enumeration literals, predefined operators, derived task
types, or derived protected types, since they are not program units.
12.b
The validity of a given address
depends on the run-time model; thus, in order to use Address clauses
correctly, one needs intimate knowledge of the run-time model.
12.c
If the Address of an object is
specified, any explicit or implicit initialization takes place as usual,
unless a pragma Import is also specified
for the object (in which case any necessary initialization is presumably
done in the foreign language).
12.d
Any compilation unit containing an attribute_reference
of a given type depends semantically on the declaration of the package in which
the type is declared, even if not mentioned in an applicable with_clause
-- see 10.1.1. In this case, it means that if a
compilation unit contains X'Address, then it depends on the declaration of System.
Otherwise, the fact that the value of Address is of a type in System wouldn't
make sense; it would violate the ``legality determinable via semantic dependences''
Language Design Principle.
12.e
AI83-00305 -- If X is a task type,
then within the body of X, X denotes the current task object; thus, X'Address
denotes the object's address.
12.f
12.g
If X is not allocated on a storage
element boundary, X'Address points at the first of the storage elements
that contains any part of X. This is important for the definition of
the Position attribute to be sensible.
Erroneous Execution
13
{erroneous execution (cause)
[partial]} If an Address is specified, it
is the programmer's responsibility to ensure that the address is valid;
otherwise, program execution is erroneous.
Implementation Advice
14
For an array X, X'Address should point at the
first component of the array, and not at the array bounds.
14.a
Ramification: On the other
hand, we have no advice to offer about discriminants and tag fields;
whether or not the address points at them is not specified by the language.
If discriminants are stored separately, then the Position of a discriminant
might be negative, or might raise an exception.
15
{recommended level of support
(Address attribute) [partial]} The recommended
level of support for the Address attribute is:
16
- X'Address should produce a useful result if X is an object
that is aliased or of a by-reference type, or is an entity whose Address
has been specified.
16.a
Reason: Aliased objects
are the ones for which the Unchecked_Access attribute is allowed; hence,
these have to be allocated on an addressable boundary anyway. Similar
considerations apply to objects of a by-reference type.
16.b
An implementation need not go
to any trouble to make Address work in other cases. For example, if an
object X is not aliased and not of a by-reference type, and the implementation
chooses to store it in a register, X'Address might return System.Null_Address
(assuming registers are not addressable). For a subprogram whose calling
convention is Intrinsic, or for a package, the implementation need not
generate an out-of-line piece of code for it.
17
- An implementation should support Address clauses for imported
subprograms.
18
- Objects (including subcomponents) that are aliased or of
a by-reference type should be allocated on storage element boundaries.
18.a
Reason: This is necessary
for the Address attribute to be useful (since First_Bit and Last_Bit
apply only to components). Implementations generally need to do this
anyway, for tasking to work properly.
19
- If the Address of an object is specified, or it is imported
or exported, then the implementation should not perform optimizations
based on assumptions of no aliases.
20
1 The specification of a link name
in a pragma Export (see B.1)
for a subprogram or object is an alternative to explicit specification of its
link-time address, allowing a link-time directive to place the subprogram or
object within memory.
21
2 The rules for the Size
attribute imply, for an aliased object X, that if X'Size = Storage_Unit,
then X'Address points at a storage element containing all of the bits
of X, and only the bits of X.
Wording Changes from Ada 83
21.a
The intended meaning of the various
attributes, and their attribute_definition_clauses,
is more explicit.
21.b
The address_clause
has been renamed to at_clause and moved
to Annex J, ``Obsolescent Features''.
One can use an Address clause (``for T'Address use ...;'') instead.
21.c
Language Design Principles
21.d
By default, the Alignment of a
subtype should reflect the ``natural'' alignment for objects of the subtype
on the machine. The Alignment, whether specified or default, should be
known at compile time, even though Addresses are generally not known
at compile time. (The generated code should never need to check at run
time the number of zero bits at the end of an address to determine an
alignment).
21.e
There are two symmetric purposes
of Alignment clauses, depending on whether or not the implementation
has control over object allocation. If the implementation allocates an
object, the implementation should ensure that the Address and Alignment
are consistent with each other. If something outside the implementation
allocates an object, the implementation should be allowed to assume that
the Address and Alignment are consistent, but should not assume stricter
alignments than that.
Static Semantics
22/1
For a prefixprefix
X that denotes a subtype or object:
23
- X'Alignment
-
The Address of an object that
is allocated under control of the implementation is an integral multiple
of the Alignment of the object (that is, the Address modulo the Alignment
is zero). The offset of a record component is a multiple of the Alignment
of the component. For an object that is not allocated under control of
the implementation (that is, one that is imported, that is allocated
by a user-defined allocator, whose Address has been specified, or is
designated by an access value returned by an instance of Unchecked_Conversion),
the implementation may assume that the Address is an integral multiple
of its Alignment. The implementation shall not assume a stricter alignment.
24
- The value of this attribute is of type universal_integer,
and nonnegative; zero means that the object is not necessarily aligned
on a storage element boundary.
24.a
Ramification: The Alignment
is passed by an allocator to the
Allocate operation; the implementation has to choose a value such that
if the address returned by Allocate is aligned as requested, the generated
code can correctly access the object.
24.b
The above mention of ``modulo''
is referring to the "mod" operator declared in System.Storage_Elements;
if X mod N = 0, then X is by definition aligned on an N-storage-element
boundary.
25
- {specifiable (of Alignment for
first subtypes and objects) [partial]} {Alignment
clause} Alignment may be specified for
first subtypes and [stand-alone] objects via an attribute_definition_clause;
the expression of such a clause shall be static, and its value nonnegative.
If the Alignment of a subtype is specified, then the Alignment of an
object of the subtype is at least as strict, unless the object's Alignment
is also specified. The Alignment of an object created by an allocator
is that of the designated subtype.
26
- If an Alignment is specified for a composite subtype
or object, this Alignment shall be equal to the least common multiple
of any specified Alignments of the subcomponent subtypes, or an integer
multiple thereof.
Erroneous Execution
27
{erroneous execution (cause)
[partial]} Program execution is erroneous
if an Address clause is given that conflicts with the Alignment.
27.a
Ramification: The user
has to either give an Alignment clause also, or else know what Alignment
the implementation will choose by default.
28
{erroneous execution (cause)
[partial]} If the Alignment is specified for
an object that is not allocated under control of the implementation,
execution is erroneous if the object is not aligned according to the
Alignment.
Implementation Advice
29
{recommended level of support
(Alignment attribute for subtypes) [partial]} The
recommended level of support for the Alignment attribute for subtypes
is:
30
- An implementation should support specified Alignments that
are factors and multiples of the number of storage elements per word,
subject to the following:
31
- An implementation need not support specified Alignments
for combinations of Sizes and Alignments that cannot be easily loaded
and stored by available machine instructions.
32
- An implementation need not support specified Alignments
that are greater than the maximum Alignment the implementation ever returns
by default.
33
{recommended
level of support (Alignment attribute for objects) [partial]}
The recommended level of support for the Alignment
attribute for objects is:
34
- Same as above, for subtypes, but in addition:
35
- For stand-alone library-level objects of statically constrained
subtypes, the implementation should support all Alignments supported
by the target linker. For example, page alignment is likely to be supported
for such objects, but not for subtypes.
36
3 Alignment is a subtype-specific
attribute.
37
4 The Alignment of a composite
object is always equal to the least common multiple of the Alignments
of its components, or a multiple thereof.
37.a
Discussion: For default
Alignments, this follows from the semantics of Alignment. For specified
Alignments, it follows from a Legality Rule stated above.
38
5 A component_clause,
Component_Size clause, or a pragma
Pack can override a specified Alignment.
38.a
Discussion: Most objects
are allocated by the implementation; for these, the implementation obeys
the Alignment. The implementation is of course allowed to make an object
more aligned than its Alignment requires -- an object whose Alignment
is 4 might just happen to land at an address that's a multiple of 4096.
For formal parameters, the implementation might want to force an Alignment
stricter than the parameter's subtype. For example, on some systems,
it is customary to always align parameters to 4 storage elements.
38.b
Hence, one might initially assume
that the implementation could evilly make all Alignments 1 by default,
even though integers, say, are normally aligned on a 4-storage-element
boundary. However, the implementation cannot get away with that -- if
the Alignment is 1, the generated code cannot assume an Alignment of
4, at least not for objects allocated outside the control of the implementation.
38.c
Of course implementations can
assume anything they can prove, but typically an implementation will
be unable to prove much about the alignment of, say, an imported object.
Furthermore, the information about where an address ``came from'' can
be lost to the compiler due to separate compilation.
38.d
The Alignment of an object that
is a component of a packed composite object will usually be 0, to indicate
that the component is not necessarily aligned on a storage element boundary.
For a subtype, an Alignment of 0 means that objects of the subtype are
not normally aligned on a storage element boundary at all. For example,
an implementation might choose to make Component_Size be 0 for an array
of Booleans, even when pragma Pack
has not been specified for the array. In this case, Boolean'Alignment
would be 0. (In the presence of tasking, this would in general be feasible
only on a machine that had atomic test-bit and set-bit instructions.)
38.e
If the machine has no particular
natural alignments, then all subtype Alignments will probably be 1 by
default.
38.f
Specifying an Alignment of 0 in
an attribute_definition_clause does
not require the implementation to do anything (except return 0 when the
Alignment is queried). However, it might be taken as advice on some implementations.
38.g
It is an error for an Address
clause to disobey the object's Alignment. The error cannot be detected
at compile time, in general, because the Address is not necessarily known
at compile time (and is almost certainly not static). We do not require
a run-time check, since efficiency seems paramount here, and Address
clauses are treading on thin ice anyway. Hence, this misuse of Address
clauses is just like any other misuse of Address clauses -- it's erroneous.
38.h
A type extension can have a stricter
Alignment than its parent. This can happen, for example, if the Alignment
of the parent is 4, but the extension contains a component with Alignment
8. The Alignment of a class-wide type or object will have to be the maximum
possible Alignment of any extension.
38.i
The recommended level of support
for the Alignment attribute is intended to reflect a minimum useful set
of capabilities. An implementation can assume that all Alignments are
multiples of each other -- 1, 2, 4, and 8 might be the only supported
Alignments for subtypes. An Alignment of 3 or 6 is unlikely to be useful.
For objects that can be allocated statically, we recommend that the implementation
support larger alignments, such as 4096. We do not recommend such large
alignments for subtypes, because the maximum subtype alignment will also
have to be used as the alignment of stack frames, heap objects, and class-wide
objects. Similarly, we do not recommend such large alignments for stack-allocated
objects.
38.j
If the maximum default Alignment
is 8 (say, Long_Float'Alignment = 8), then the implementation can refuse
to accept stricter alignments for subtypes. This simplifies the generated
code, since the compiler can align the stack and class-wide types to
this maximum without a substantial waste of space (or time).
38.k
Note that the recommended level
of support takes into account interactions between Size and Alignment.
For example, on a 32-bit machine with 8-bit storage elements, where load
and store instructions have to be aligned according to the size of the
thing being loaded or stored, the implementation might accept an Alignment
of 1 if the Size is 8, but might reject an Alignment of 1 if the Size
is 32. On a machine where unaligned loads and stores are merely inefficient
(as opposed to causing hardware traps), we would expect an Alignment
of 1 to be supported for any Size.
Wording Changes from Ada 83
38.l
The nonnegative part is missing
from RM83 (for mod_clauses, nee
alignment_clauses, which are an
obsolete version of Alignment clauses).
Static Semantics
39/1
For a prefixprefix
X that denotes an object:
40
- X'Size
-
Denotes the size in bits of the
representation of the object. The value of this attribute is of the type
universal_integer.
40.a
Ramification: Note that
Size is in bits even if Machine_Radix is 10. Each decimal digit (and
the sign) is presumably represented as some number of bits.
41
- {specifiable (of Size for stand-alone
objects) [partial]} {Size
clause} Size may be specified for [stand-alone]
objects via an attribute_definition_clause;
the expression of such a clause shall be static and its value nonnegative.
Implementation Advice
42
{recommended
level of support (Size attribute) [partial]} The
recommended level of support for the Size attribute of objects is:
43
- A Size clause should be supported for an object if the
specified Size is at least as large as its subtype's Size, and corresponds
to a size in storage elements that is a multiple of the object's Alignment
(if the Alignment is nonzero).
Static Semantics
44
For every subtype
S:
45
- S'Size
-
If S is definite, denotes the
size [(in bits)] that the implementation would choose for the following
objects of subtype S:
46
- A record component of subtype S when the record type is
packed.
47
- The formal parameter of an instance of Unchecked_Conversion
that converts from subtype S to some other subtype.
48
- If S is indefinite, the meaning is implementation
defined. The value of this attribute is of the type universal_integer.
{specifiable (of Size for first subtypes) [partial]}
{Size clause} The
Size of an object is at least as large as that of its subtype, unless
the object's Size is determined by a Size clause, a component_clause,
or a Component_Size clause. Size may be specified for first subtypes
via an attribute_definition_clause;
the expression of such a clause shall be static and its value nonnegative.
48.a
Implementation defined: The
meaning of Size for indefinite subtypes.
48.b
Reason:
The effects of specifying the Size of a subtype are:
48.c
- Unchecked_Conversion works in a predictable manner.
48.d
- A composite type cannot be packed so tightly as to override
the specified Size of a component's subtype.
48.e
- Assuming the Implementation Advice is obeyed, if the specified
Size allows independent addressability, then the Size of certain objects
of the subtype should be equal to the subtype's Size. This applies to
stand-alone objects and to components (unless a component_clause
or a Component_Size clause applies).
48.f
A component_clause
or a Component_Size clause can cause an object to be smaller than its
subtype's specified size. A pragma
Pack cannot; if a component subtype's size is specified, this limits
how tightly the composite object can be packed.
48.g
The Size of a class-wide (tagged)
subtype is unspecified, because it's not clear what it should mean; it
should certainly not depend on all of the descendants that happen to
exist in a given program. Note that this cannot be detected at compile
time, because in a generic unit, it is not necessarily known whether
a given subtype is class-wide. It might raise an exception on some implementations.
48.h
Ramification:
A Size clause for a numeric subtype need not affect the underlying
numeric type. For example, if I say:
48.i
type S is range 1..2;
for S'Size use 64;
48.j
I am not guaranteed that S'Base'Last
>= 2**63-1, nor that intermediate results will be represented in 64
bits.
48.k
Reason: There is no need
to complicate implementations for this sort of thing, because the right
way to affect the base range of a type is to use the normal way of declaring
the base range:
48.l
type Big is range -2**63 .. 2**63 - 1;
subtype Small is Big range 1..1000;
48.m
Ramification: The Size
of a large unconstrained subtype (e.g. String'Size) is likely to raise
Constraint_Error, since it is a nonstatic expression of type universal_integer
that might overflow the largest signed integer type. There is no requirement
that the largest integer type be able to represent the size in bits of
the largest possible object.
Implementation Requirements
49
In an implementation, Boolean'Size shall be 1.
Implementation Advice
50
If the
Size of a subtype is specified, and allows for efficient independent addressability
(see
9.10) on the target architecture, then the Size
of the following objects of the subtype should equal the Size of the subtype:
51
- Aliased objects (including components).
52
- Unaliased components, unless the Size of the component
is determined by a component_clause
or Component_Size clause.
52.a
Ramification: Thus, on
a typical 32-bit machine, ``for S'Size use 32;'' will guarantee
that aliased objects of subtype S, and components whose subtype is S,
will have Size = 32 (assuming the implementation chooses to obey this
Implementation Advice). On the other hand, if one writes, ``for
S2'Size use 5;'' then stand-alone objects of subtype S2 will typically
have their Size rounded up to ensure independent addressability.
52.b
Note that ``for S'Size
use 32;'' does not cause things like formal parameters to have
Size = 32 -- the implementation is allowed to make all parameters be
at least 64 bits, for example.
52.c
Note that ``for S2'Size
use 5;'' requires record components whose subtype is S2 to be
exactly 5 bits if the record type is packed. The same is not true of
array components; their Size may be rounded up to the nearest factor
of the word size.
52.d
Implementation Note: {gaps}
On most machines, arrays don't contain gaps between
components; if the Component_Size is greater than the Size of the component
subtype, the extra bits are generally considered part of each component,
rather than gaps between components. On the other hand, a record might
contain gaps between components, depending on what sorts of loads, stores,
and masking operations are generally done by the generated code.
52.e
For an array, any extra bits stored
for each component will generally be part of the component -- the whole
point of storing extra bits is to make loads and stores more efficient
by avoiding the need to mask out extra bits. The PDP-10 is one counter-example;
since the hardware supports byte strings with a gap at the end of each
word, one would want to pack in that manner.
53
A Size clause on a composite subtype should not
affect the internal layout of components.
53.a
Reason: That's what Pack
pragmas, record_representation_clauses,
and Component_Size clauses are for.
54
{recommended
level of support (Size attribute) [partial]} The
recommended level of support for the Size attribute of subtypes is:
55
- The Size (if not specified) of a static discrete or fixed
point subtype should be the number of bits needed to represent each value
belonging to the subtype using an unbiased representation, leaving space
for a sign bit only if the subtype contains negative values. If such
a subtype is a first subtype, then an implementation should support a
specified Size for it that reflects this representation.
55.a
Implementation Note: This
applies to static enumeration subtypes, using the internal codes used
to represent the values.
55.b
For a two's-complement machine,
this implies that for a static signed integer subtype S, if all values
of S are in the range 0 .. 2n-1,
or all values of S are in the range -2n-1
.. 2n-1-1,
for some n less than or equal to the word size, then S'Size should
be <= the smallest such n. For a one's-complement machine,
it is the same except that in the second range, the lower bound ``-2n-1''
is replaced by ``-2n-1+1''.
55.c
If an integer subtype (whether
signed or unsigned) contains no negative values, the Size should not
include space for a sign bit.
55.d
Typically, the implementation
will choose to make the Size of a subtype be exactly the smallest such
n. However, it might, for example, choose a biased representation,
in which case it could choose a smaller value.
55.e
On most machines, it is in general
not a good idea to pack (parts of) multiple stand-alone objects into
the same storage element, because (1) it usually doesn't save much space,
and (2) it requires locking to prevent tasks from interfering with each
other, since separate stand-alone objects are independently addressable.
Therefore, if S'Size = 2 on a machine with 8-bit storage elements, the
size of a stand-alone object of subtype S will probably not be 2. It
might, for example, be 8, 16 or 32, depending on the availability and
efficiency of various machine instructions. The same applies to components
of composite types, unless packing, Component_Size, or record layout
is specified.
55.f
For an unconstrained discriminated
object, if the implementation allocates the maximum possible size, then
the Size attribute should return that maximum possible size.
55.g
Ramification: The Size
of an object X is not usually the same as that of its subtype S. If X
is a stand-alone object or a parameter, for example, most implementations
will round X'Size up to a storage element boundary, or more, so X'Size
might be greater than S'Size. On the other hand, X'Size cannot be less
than S'Size, even if the implementation can prove, for example, that
the range of values actually taken on by X during execution is smaller
than the range of S.
55.h
For example, if S is a first integer
subtype whose range is 0..3, S'Size will be probably be 2 bits, and components
of packed composite types of this subtype will be 2 bits (assuming Storage_Unit
is a multiple of 2), but stand-alone objects and parameters will probably
not have a size of 2 bits; they might be rounded up to 32 bits, for example.
On the other hand, Unchecked_Conversion will use the 2-bit size, even
when converting a stand-alone object, as one would expect.
55.i
Another reason for making the
Size of an object bigger than its subtype's Size is to support the run-time
detection of uninitialized variables. {uninitialized variables
[partial]} The implementation might add an extra
value to a discrete subtype that represents the uninitialized state,
and check for this value on use. In some cases, the extra value will
require an extra bit in the representation of the object. Such detection
is not required by the language. If it is provided, the implementation
has to be able to turn it off. For example, if the programmer gives a
record_representation_clause or
Component_Size clause that makes a component too small to allow the extra
bit, then the implementation will not be able to perform the checking
(not using this method, anyway).
55.j
The
fact that the size of an object is not necessarily the same as its subtype
can be confusing:
55.k
type Device_Register is range 0..2**8 - 1;
for Device_Register'Size use 8; -- Confusing!
My_Device : Device_Register;
for My_Device'Address use To_Address(16#FF00#);
55.l
The programmer might think that
My_Device'Size is 8, and that My_Device'Address points at an 8-bit location.
However, this is not true. In Ada 83 (and in Ada 95), My_Device'Size
might well be 32, and My_Device'Address might well point at the high-order
8 bits of the 32-bit object, which are always all zero bits. If My_Device'Address
is passed to an assembly language subprogram, based on the programmer's
assumption, the program will not work properly.
55.m
Reason: It is not reasonable
to require that an implementation allocate exactly 8 bits to all objects
of subtype Device_Register. For example, in many run-time models, stand-alone
objects and parameters are always aligned to a word boundary. Such run-time
models are generally based on hardware considerations that are beyond
the control of the implementer. (It is reasonable to require that an
implementation allocate exactly 8 bits to all components of subtype Device_Register,
if packed.)
55.n
Ramification:
The correct way to write the above code is like this:
55.o
type Device_Register is range 0..2**8 - 1;
My_Device : Device_Register;
for My_Device'Size use 8;
for My_Device'Address use To_Address(16#FF00#);
55.p
If the implementation cannot accept
8-bit stand-alone objects, then this will be illegal. However, on a machine
where an 8-bit device register exists, the implementation will probably
be able to accept 8-bit stand-alone objects. Therefore, My_Device'Size
will be 8, and My_Device'Address will point at those 8 bits, as desired.
55.q
If an object of subtype Device_Register
is passed to a foreign language subprogram, it will be passed according
to that subprogram's conventions. Most foreign language implementations
have similar run-time model restrictions. For example, when passing to
a C function, where the argument is of the C type char* (that is, pointer
to char), the C compiler will generally expect a full word value, either
on the stack, or in a register. It will not expect a single byte.
Thus, Size clauses for subtypes really have nothing to do with passing
parameters to foreign language subprograms.
56
- For a subtype implemented with levels of indirection, the
Size should include the size of the pointers, but not the size of what
they point at.
56.a
Ramification: For example,
if a task object is represented as a pointer to some information (including
a task stack), then the size of the object should be the size of the
pointer. The Storage_Size, on the other hand, should include the size
of the stack.
57
6 Size is a subtype-specific
attribute.
58
7 A component_clause
or Component_Size clause can override a specified Size. A pragma
Pack cannot.
Wording Changes from Ada 83
58.a
The requirement for a nonnegative
value in a Size clause was not in RM83, but it's hard to see how it would
make sense. For uniformity, we forbid negative sizes, rather than letting
implementations define their meaning.
Static Semantics
59/1
For a prefixprefix
T that denotes a task object [(after any implicit dereference)]:
60
- T'Storage_Size
-
Denotes the number of storage
elements reserved for the task. The value of this attribute is of the
type universal_integer. The Storage_Size includes the size of
the task's stack, if any. The language does not specify whether or not
it includes other storage associated with the task (such as the ``task
control block'' used by some implementations.) If a pragma
Storage_Size is given, the value of the Storage_Size attribute is at
least the value specified in the pragma.
60.a
Ramification: The value
of this attribute is never negative, since it is impossible to ``reserve''
a negative number of storage elements.
60.b
If the implementation chooses
to allocate an initial amount of storage, and then increase this as needed,
the Storage_Size cannot include the additional amounts (assuming the
allocation of the additional amounts can raise Storage_Error); this is
inherent in the meaning of ``reserved.''
60.c
The implementation is allowed
to allocate different amounts of storage for different tasks of the same
subtype.
60.d
Storage_Size is also defined for access
subtypes -- see 13.11.
61
[
{Storage_Size clause: See also
pragma Storage_Size} A
pragma
Storage_Size specifies the amount of storage to be reserved for the execution
of a task.]
Syntax
62
The form of
a pragma Storage_Size is as follows:
63
pragma Storage_Size(
expression);
64
A pragma
Storage_Size is allowed only immediately within a task_definition.
Name Resolution Rules
65
{expected type (Storage_Size
pragma argument) [partial]} The
expression
of a
pragma Storage_Size is expected
to be of any integer type.
Dynamic Semantics
66
A
pragma
Storage_Size is elaborated when an object of the type defined by the
immediately enclosing
task_definition
is created.
{elaboration (Storage_Size pragma) [partial]}
For the elaboration of a
pragma
Storage_Size, the
expression is
evaluated; the Storage_Size attribute of the newly created task object
is at least the value of the
expression.
66.a
Ramification: The implementation
is allowed to round up a specified Storage_Size amount. For example,
if the implementation always allocates in chunks of 4096 bytes, the number
200 might be rounded up to 4096. Also, if the user specifies a negative
number, the implementation has to normalize this to 0, or perhaps to
a positive number.
67
{Storage_Check [partial]}
{check, language-defined (Storage_Check)}
{Storage_Error (raised by failure
of run-time check)} At the point of task
object creation, or upon task activation, Storage_Error is raised if
there is insufficient free storage to accommodate the requested Storage_Size.
Static Semantics
68/1
For a prefixprefix
X that denotes an array subtype or array object [(after any implicit
dereference)]:
69
- X'Component_Size
-
Denotes the size in bits of components
of the type of X. The value of this attribute is of type universal_integer.
70
- {specifiable (of Component_Size
for array types) [partial]} {Component_Size
clause} Component_Size may be specified
for array types via an attribute_definition_clause;
the expression of such a clause shall be static, and its value nonnegative.
70.a
Implementation Note: The
intent is that the value of X'Component_Size is always nonnegative. If
the array is stored ``backwards'' in memory (which might be caused by
an implementation-defined pragma), X'Component_Size is still positive.
70.b
Ramification: For an array
object A, A'Component_Size = A(I)'Size for any index I.
Implementation Advice
71
{recommended
level of support (Component_Size attribute) [partial]} The
recommended level of support for the Component_Size attribute is:
72
- An implementation need not support specified Component_Sizes
that are less than the Size of the component subtype.
73
- An implementation should support specified Component_Sizes
that are factors and multiples of the word size. For such Component_Sizes,
the array should contain no gaps between components. For other Component_Sizes
(if supported), the array should contain no gaps between components when
packing is also specified; the implementation should forbid this combination
in cases where it cannot support a no-gaps representation.
73.a
Ramification: For example,
if Storage_Unit = 8, and Word_Size = 32, then the user is allowed to
specify a Component_Size of 1, 2, 4, 8, 16, and 32, with no gaps. In
addition, n*32 is allowed for positive integers n, again
with no gaps. If the implementation accepts Component_Size = 3, then
it might allocate 10 components per word, with a 2-bit gap at the end
of each word (unless packing is also specified), or it might not have
any internal gaps at all. (There can be gaps at either end of the array.)
Static Semantics
73.1/1
{
8652/0009}
The following operational attribute is defined: External_Tag.
74/1
{
8652/0009}
For every subtype S of a tagged type
T (specific or class-wide)
, the
following attribute is defined:
75/1
- S'External_Tag
- {8652/0040}
{External_Tag clause} {specifiable
(of External_Tag for a tagged type) [partial]} S'External_Tag
denotes an external string representation for S'Tag; it is of the predefined
type String. External_Tag may be specified for a specific tagged type via
an attribute_definition_clause; the expression
of such a clause shall be static. The default external tag representation
is implementation defined. See 3.9.2 and 13.13.2.
The value of External_Tag is never inherited[; the default value is always
used unless a new value is directly specified for a type].
75.a
Implementation defined: The
default external representation for a type tag.
Implementation Requirements
76
In an implementation, the default external tag
for each specific tagged type declared in a partition shall be distinct,
so long as the type is declared outside an instance of a generic body.
If the compilation unit in which a given tagged type is declared, and
all compilation units on which it semantically depends, are the same
in two different partitions, then the external tag for the type shall
be the same in the two partitions. What it means for a compilation unit
to be the same in two different partitions is implementation defined.
At a minimum, if the compilation unit is not recompiled between building
the two different partitions that include it, the compilation unit is
considered the same in the two partitions.
76.a
Implementation defined: What
determines whether a compilation unit is the same in two different partitions.
76.b
Reason: These requirements
are important because external tags are used for input/output of class-wide
types. These requirements ensure that what is written by one program
can be read back by some other program so long as they share the same
declaration for the type (and everything it depends on).
76.c
The user may specify the external
tag if (s)he wishes its value to be stable even across changes to the
compilation unit in which the type is declared (or changes in some unit
on which it depends).
76.d
We use a String rather than a
Storage_Array to represent an external tag for portability.
76.e
Ramification: Note that
the characters of an external tag need not all be graphic characters.
In other words, the external tag can be a sequence of arbitrary 8-bit
bytes.
77
8 The following language-defined
attributes are specifiable, at least for some of the kinds of entities
to which they apply: Address, Size, Component_Size, Alignment, External_Tag,
Small, Bit_Order, Storage_Pool, Storage_Size, Write, Output, Read, Input,
and Machine_Radix.
78
9 It follows from the general rules
in 13.1 that if one writes ``for X'Size use
Y;'' then the X'Size attribute_reference
will return Y (assuming the implementation allows the Size clause). The same
is true for all of the specifiable attributes except Storage_Size.
78.a
Ramification: An implementation
may specify that an implementation-defined attribute is specifiable for
certain entities. This follows from the fact that the semantics of implementation-defined
attributes is implementation defined. An implementation is not allowed
to make a language-defined attribute specifiable if it isn't.
Examples
79
Examples of
attribute definition clauses:
80
Byte : constant := 8;
Page : constant := 2**12;
81
type Medium is range 0 .. 65_000;
for Medium'Size use 2*Byte;
for Medium'Alignment use 2;
Device_Register : Medium;
for Device_Register'Size use Medium'Size;
for Device_Register'Address use System.Storage_Elements.To_Address(16#FFFF_0020#);
82
type Short is delta 0.01 range -100.0 .. 100.0;
for Short'Size use 15;
83
for Car_Name'Storage_Size use -- specify access type's storage pool size
2000*((Car'Size/System.Storage_Unit) +1); -- approximately 2000 cars
84
function My_Read(Stream : access Ada.Streams.Root_Stream_Type'Class)
return T;
for T'Read use My_Read; -- see 13.13.2
85
10 Notes on the examples:
In the Size clause for Short, fifteen bits is the minimum necessary,
since the type definition requires Short'Small <= 2**(-7).
Extensions to Ada 83
85.a
{extensions to Ada 83}
The syntax rule for length_clause
is replaced with the new syntax rule for attribute_definition_clause,
and it is modified to allow a name
(as well as an expression).
Wording Changes from Ada 83
85.b
The syntax rule for attribute_definition_clause
now requires that the prefix of the attribute
be a local_name; in Ada 83 this
rule was stated in the text.
85.c
In Ada 83, the relationship between
a representation_clause specifying
a certain aspect and an attribute that queried that aspect was unclear.
In Ada 95, they are the same, except for certain explicit exceptions.
Contents Index Previous Next Legal