E.4 Representation Clauses

The Ada 83 reference manual was quite vague in describing both the minimal
required implementation of representation clauses, and also their precise
effects. The Ada 95 reference manual is much more explicit, but the minimal
set of capabilities required in Ada 95 is quite limited.

GNAT implements the full required set of capabilities described in the
Ada 95 reference manual, but also goes much beyond this, and in particular
an effort has been made to be compatible with existing Ada 83 usage to the
greatest extent possible.

A few cases exist in which Ada 83 compiler behavior is incompatible with
requirements in the Ada 95 reference manual. These are instances of
intentional or accidental dependence on specific implementation dependent
characteristics of these Ada 83 compilers. The following is a list of
the cases most likely to arise in existing legacy Ada 83 code.

Implicit Packing

Some Ada 83 compilers allowed a Size specification to cause implicit
packing of an array or record. This could cause expensive implicit
conversions for change of representation in the presence of derived
types, and the Ada design intends to avoid this possibility.
Subsequent AI's were issued to make it clear that such implicit
change of representation in response to a Size clause is inadvisable,
and this recommendation is represented explicitly in the Ada 95 RM
as implementation advice that is followed by GNAT.
The problem will show up as an error
message rejecting the size clause. The fix is simply to provide
the explicit pragma Pack, or for more fine tuned control, provide
a Component_Size clause.

Meaning of Size Attribute

The Size attribute in Ada 95 for discrete types is defined as being the
minimal number of bits required to hold values of the type. For example,
on a 32-bit machine, the size of Natural will typically be 31 and not
32 (since no sign bit is required). Some Ada 83 compilers gave 31, and
some 32 in this situation. This problem will usually show up as a compile
time error, but not always. It is a good idea to check all uses of the
'Size attribute when porting Ada 83 code. The GNAT specific attribute
Object_Size can provide a useful way of duplicating the behavior of
some Ada 83 compiler systems.

Size of Access Types

A common assumption in Ada 83 code is that an access type is in fact a pointer,
and that therefore it will be the same size as a System.Address value. This
assumption is true for GNAT in most cases with one exception. For the case of
a pointer to an unconstrained array type (where the bounds may vary from one
value of the access type to another), the default is to use a “fat pointer”,
which is represented as two separate pointers, one to the bounds, and one to
the array. This representation has a number of advantages, including improved
efficiency. However, it may cause some difficulties in porting existing Ada 83
code which makes the assumption that, for example, pointers fit in 32 bits on
a machine with 32-bit addressing.

To get around this problem, GNAT also permits the use of “thin pointers” for
access types in this case (where the designated type is an unconstrained array
type). These thin pointers are indeed the same size as a System.Address value.
To specify a thin pointer, use a size clause for the type, for example:

type X is access all String;
for X'Size use Standard'Address_Size;

which will cause the type X to be represented using a single pointer.
When using this representation, the bounds are right behind the array.
This representation is slightly less efficient, and does not allow quite
such flexibility in the use of foreign pointers or in using the
Unrestricted_Access attribute to create pointers to non-aliased objects.
But for any standard portable use of the access type it will work in
a functionally correct manner and allow porting of existing code.
Note that another way of forcing a thin pointer representation
is to use a component size clause for the element size in an array,
or a record representation clause for an access field in a record.