TOC PREV NEXT INDEX DOC LIST MASTER INDEX



Sizes of Objects

This chapter describes the sizes of both scalar and composite objects. The first section discusses concepts of size that apply to all object types but are most important for the composite types. The remaining section discusses individual types:


Concepts for Object Sizes

This section describes the terminology you use to discuss object sizes and provides an overview of how storage size is determined.

Minimum, Default, Packed, and Unpacked Sizes

Use the following terms to describe the size of an object:

Determination of Storage Size

Top-level scalar and access objects are stored using their unpacked size. (A top-level object is an object that is not a component of any array or record). Components of composite objects that do not have either pragma Pack or a record representation clause are also stored using the unpacked size.

Components of composite objects having pragma Pack are stored using the packed size.

Fields of records having record representation clauses can be stored in any number of bits ranging from the minimum size to the default size of the field type. If a scalar- or composite-type component field is specified to be smaller than the default size, a filler field is introduced and the data is left-justified. Restrictions on Representation Specifications can be found in the Ada Compiler Reference.


Sizes for Specific Types

This section describes the sizes and storage for the following types:

Discrete Types

'Size clauses for discrete types affect sizes by changing the packed and unpacked sizes. When there is no 'Size clause, the packed and unpacked sizes are the minimum and default sizes, respectively. 'Size clauses with values outside the minimum and maximum sizes cause a semantic error. Within that range, two cases depend on the value specified by the clause:

Size examples appear in Table 7.

Note: Actual sizes vary by the compiler variant being used. See the "Declarations and Types" section in the Ada Compiler Reference for sizes specific to the compiler variant you are using.

Table 7 Size Examples for Rational Ada
Example type declaration
Minimum size
Defaultsize
Maximum size
Integer
32
32
32
Long_Integer
64
64
64
Boolean
1
8
32
Float
32
32
32
Long_Float
64
64
64
Type Byte is range 0 .. 255
8
32
32
Type Primary is (Red, Blue, Yellow)
2
8
32
Type X is (Normal, Read_Error, Write_Error); for X use (7, 15, 31);
5
8
32
Type Ary is array (1 .. 100) of Boolean
100
800
n/a

Integer Types

The default size of a first-named integer subtype is 32.

The 'Size clause is supported for non-derived and derived integer types. The effect of a 'Size clause on minimum size is shown in the following example:

where n is a static integer expression.

Table 8 shows the effect of n on the packed and unpacked sizes.

.
Table 8 Example of Effect of 'Size Clause
'Size clause
Packed size
Unpacked size
No 'Size clause
8
32
Use 8
8
32
Use 12
12
32

Enumeration Types

For an enumeration type with n elements, the default internal integer representation ranges from 0 to n-1.

Enumeration and length clauses are permitted on derived types. However, this might generate additional code when parent/derived types are converted to each other.

For predefined type Character, the value returned by the 'Size attribute is 8, and the minimum size is 8. User-defined character types are like ordinary enumeration types and can have a minimum size that is less than 8.

Length clauses are supported for both nonderived and derived enumeration types. The effect of a length clause on representation is shown in the following example:

where n is a static integer expression.

Table 9 lists the packed and unpacked sizes for different values of n.

Table 9 Example of Enumeration Type Sizes
Length clause
Packed size
Unpacked size
No length clause
2
8
Use 4
4
8
Use 12
12
16
Use 16
16
16
Use 20
20
32
Use 32
32
32

Floating-Point Types

The internal representations for floating-point types are the 32-bit and 64-bit floating-point representations as defined by the host architecture.

Fixed-Point Types

Fixed-point types are represented internally as integers. The integer representation is computed by scaling (dividing) the fixed-point number by the actual small implied by the fixed-point type declaration. Actual small is defined to be the nearest power of 2 that is greater than the smallest possible value of the fixed-point type. The values that are exactly representable are those that are precise multiples of the actual small; numbers between those values are represented by the closest exact multiple. For example, in the declaration:

the integer value used to represent the lower bound of the type is 󈝶.0 / (1/128), or �, because the actual small, representing 0.01, is 1/128. In the example:

the integer value used to represent the lower bound of the type is �, which is the closest exact multiple of the actual small. (This is 󈝶.6/(1/128) = �.8; the nearest integer representation is �.)

The size of the representation is 8, 16, 32, or 64.

'Size and 'Small are supported for both nonderived and derived types. The value given in a 'Small clause for a fixed type must be a positive static real number. The value need not be a power of 2. By Ada rules, it cannot be greater than the delta of the base type.

Access Types and Task Types

Access and task objects have a size of 32 bits or 64 bits, depending on your system. The 'Storage_Size length clause is allowed for access and task types. The value given in a 'Storage_Size clause can be any integer expression, and it is not required to be static. Static expressions larger than Integer'Last will generate compilation warnings; however, a Constraint_Error exception will be raised at run time.

For access types, the 'Storage_Size clause is used to specify the size of the access type's collection. If a 'Storage_Size clause has been applied to an access type, the collection is nonextensible. For task types, the clause determines the stack size.

For access types, memory allocation for the collection is controlled by pragma Collection_Policy. For more information about pragma Collection_Policy, refer to the Ada Compiler Reference.

A value (either static or not) of 0 is allowed. In this case, no collection or task stack space will be allocated, and a Storage_Error exception will be raised at run time if any attempt is made to allocate or deallocate from the collection or activate the task. Negative values are also allowed by access types; however, these generate a Storage_Error exception when the type is elaborated, even if no attempt is made to allocate or deallocate objects belonging to the collection.

Record Types

In the absence of a record representation clause, a record type has two basic representations: unpacked and packed.

In the unpacked representation, each record component starts on a storage-unit boundary, and alignment filler may be introduced between components to cause the components to be aligned properly. For example, an integer component will be aligned so that it starts on a longword boundary.

In the packed representation, a component whose size is less than 32 bits will occupy exactly the number of bits in its minimum size; such components might not start on storage-unit boundaries. At present, alignment filler is not eliminated in the packed representation.

The criteria for selecting which representation to use are the same as described in Array Types.

In either case, may lay out the record fields in a different order than that used in the type declaration for the record. This is done in an attempt to satisfy alignment requirements without introducing unnecessary alignment filler. When a convention of C is specified for a record type (pragma Convention), the layout of the record is C-compatible (i.e. the same layout as would be generated by the C compiler for a corresponding C struct). In particular, the compiler does not reorder fields in this case.

If a record representation clause is present, it may mention some or all of the fields in the record. Those fields mentioned in the clause will be laid out according to its rules; the remaining fields are then laid out according to the default algorithms, starting at the first storage unit past the last field mentioned in the clause. This is the case even if the clause leaves holes that are big enough to contain some of the fields not mentioned.

In a discriminated record, this rule has an important consequence: If one of the discriminants is not mentioned in the clause, it will be placed after all of the fields in the largest variant part (as specified by the clause). Even though some of the variant parts are smaller than others, constrained copies of the record selecting those variants will be as large as copies of the record with the largest variant.

A record representation clause cannot mention a field whose size is not known at compile time (this includes fields whose size depends on a discriminant).

Unconstrained records with default values are given the maximum sizes for objects of the values' types.

Array Types

For a given array type, Apex is capable of using one of two representations, known as the unpacked and packed representations.

In the unpacked representation, each array component starts on a storage-unit boundary, and filler (of up to three storage units) can be introduced between components to cause them to be aligned properly. This alignment filler is sometimes needed when the component is a record type or contains record types.

The packed representation for an array type differs from the unpacked representation if the type satisfies one of the following mutually exclusive requirements:

If neither of the two situations above holds, the packed representation is the same as the unpacked representation.

Rational Ada uses the unpacked representation when:

uses the packed representation when:

In any case, if the packed representation is too large for an explicit length clause, a compilation error results.

Change of representation is supported for arrays. Therefore, pragma Pack on a derived array type is honored, and length clauses on derived array types are permitted.

Array Storage

The elements of an array are stored in contiguous memory locations with the first array component stored at the lowest address. Components of an array can have gaps between them as described above.

For example, one-dimensional arrays of type A1 are laid out as shown in Table 10 :

Similarly, two-dimensional arrays of type A2 have the layout shown in Table 11:

Dope Vectors

Associated with every array is information about its size and the bounds of each of its dimensions. This information is represented in the form of a dope vector (sometimes called an array descriptor). For constrained array types whose size is known at compile time, the dope vector is an internal construct that has no consequences for the representation of the array itself and A'Dope_Address returns zero.

However, when an array of an unconstrained type is used in the following way, the array's dope vector is included as part of the array's representation and A'Dope_Address returns a nonzero System.Address:

The array's type is the designated type of an access type. For example:

As shown, each of the arrays allocated in the access type's collection can have different bounds. Consequently, a dope vector is needed to describe each array.

The dope vector for an array contains bounds and size information for each of its dimensions. For each dimension, this information is represented in
3* Long_Integer'Size bit triples. Thus, if an array A has N dimensions, the triple for a given dimension K (K < N) contains:


Rational Software Corporation 
http://www.rational.com
support@rational.com
techpubs@rational.com
Copyright © 1993-2002, Rational Software Corporation. All rights reserved.
TOC PREV NEXT INDEX DOC LIST MASTER INDEX TECHNOTES APEX TIPS