Storage mapping of Pascal arrays, records, and variant records is described in the first part of this chapter. Ranges are discussed in the second part. Alignment, size and value ranges for the various data types are described in the third part. The last section discusses rules for set sizing.
Pascal maps arrays and records into storage like C maps arrays and structures.
An array has the same boundary requirements as the data type specified for the array. The size of an array is the size of the data type, multiplied by the number of elements.
For example, for the following declaration,
x : array [1..2, 1..3] of double; |
the size of the resulting array is 48 bytes (2*3*8, where 8 is the size of the double-floating point type in bytes).
Each member of a record begins at an offset from the record base. The offset corresponds to the order in which a member is declared; the first member is at offset 0.
The size of a record in the object file is the size of its combined members plus padding added, where necessary, by the compiler.
The following rules apply to records:
Records must align on the same boundary as that required by the member with the most restrictive boundary requirement. These are the boundary requirements, listed by increasing degree of restrictiveness:
byte
halfword
doubleword
The compiler terminates the record on the same alignment boundary on which it begins. For example, if a record begins on an even-byte boundary, it also ends on an even-byte boundary.
This example shows a record in code:
type S = record
v : integer;
n : array [1..10] of char;
end;
|
Figure 3-1 shows how it is mapped in storage.
Note that the length of the record is 16 bytes, even though the byte count as defined by the v:integer and the n:array[1..10] of char components is only 14. Because integer has a stricter boundary requirement (word boundary) than char (byte boundary), the record must end on a word boundary (a byte offset divisible by four). The compiler therefore adds two bytes of padding to meet this requirement.
An array of data records illustrates the reason for this requirement. For example, if the above record were the element-type of an array, some of the v:integer components would not be aligned properly without the two-byte pad.
This example shows a record with different alignment in code:
type S = record
n : packed array [1..10] of char;
v : integer;
end;
|
Figure 3-2 shows how it is mapped in storage.
In the example, the alignment requirements cause padding to appear in the middle of the record. Note that the size of the record remains 16 bytes, but two bytes of padding follow the n component to align v on a word boundary.
A variant record must align on the same boundary as the member with the most restrictive boundary requirement.
These are the boundary requirements, listed by increasing degree of restrictiveness:
byte
halfword
word
doubleword
For example, a variant record containing integer, char, and double data types must align on a doubleword boundary, as required by the double data type.
Ranges in a packed record are packed from the most-significant bit to the least-significant bit in a word.
This example shows a packed record in code:
type virtual_address = packed record
offset : 0..4095; (* 12 bits *)
page : 0..1023; (* 10 bits *)
segment : 0..511; (* 9 bits *)
supervisor : 0..1; (* 1 bit *)
end;
|
Figure 3-3 shows how it is mapped in storage.
Ranges in an unpacked record are packed from the most-significant bit to the least-significant bit, but each range is aligned to the appropriate boundary. This example shows an unpacked record in code:
type virtual_address = record
offset : 0..4095; (* 12 bits *)
page : 0..1023; (* 10 bits *)
segment : 0..511; (* 9 bits *)
supervisor : 0..1; (* 1 bit *)
end;
|
Figure 3-4 shows how it is mapped in storage.
For unpacked records, the compiler aligns a non-range element that follows a range declaration to the next boundary appropriate for its type.
This example shows another unpacked record in code:
var x : record
a : 0..7; (* 3 bits packed *)
b : char; (* 8 bits *)
c : -32768..32767; (* 16 bits *)
end;
|
Figure 3-5 shows how it is mapped in storage.
For a packed record, the computer bit-aligns booleans, chars, and ranges. All other types are word or double-word aligned as appropriate for the type. This example shows the same code as above in a packed record and its mapping in storage:
var x : packed record
a : 0..7; (* 3 bits *)
b : char; (* 8 bits *)
c : -32768..32767 (* 16 bits *)
end;
|
Figure 3-6 shows how it is mapped in storage.
This section describes how the Pascal compiler implements size, alignment, and value ranges for the various data types.
Table 3-1 shows the value ranges for the Pascal scalar types.
Table 3-1. Value Ranges by Data Type
Scalar Type | Value Ranges |
|---|---|
boolean | 0 or 1 |
char | 0..127 |
integer | -231..231-1 |
cardinal | 0..232-1 |
real | See Note |
double | See Note |
Table 3-2 and Table 3-3 show the approximate valid ranges for real and double. Enumerated types with n elements are treated in the same manner as the integer subrange 0..n-1.
Table 3-2. Real and Double Maximum Values
Type | Maximum Value |
|---|---|
real | 3.40282356*1038 |
double | 1.7976931348623158*10308 |
Table 3-3. Real and Double Minimum Values
| Minimum Value |
|
|---|---|---|
Type | Denormalized | Normalized |
real | 1.40129846 * 10-46 | 1.17 549429 * 10-38 |
double | 4.9406564584124654*10-324 | 2.2250738585072012*10-308 |
Table 3-4, following, lists size and alignment parameters for unpacked records. See Section 3.4, “Rules for Set Sizes,” for rules about specifying the upper and lower bounds of s
Table 3-4. Size and Alignment of Data Types in Unpacked Records or Arrays
| Unpacked Records or Arrays (variables or fields) |
|
|---|---|---|
Type | Size | Alignment |
boolean | 8 | byte |
char | 8 | byte |
integer | 32 | word |
cardinal | 32 | word |
pointer | 32 | word |
file | 32 | word |
real | 32 | word |
double | 64 | doubleword |
subrange of: |
|
|
0..255 or -128..127 | 8 | byte |
0..65535 or -32768..32767 | 16 | halfword |
0..232 - 1 |
|
|
-231..-231 - 1 | 32 | word |
set of char | 128 | word |
set of a..b | See note | word |
![]() | Note: For unpacked records, the compiler uses the following formula for determining the size of the set of a..b: |
size=[b2⌋ - ⌊a/32⌋ + 1 words
|
The notation [ x ] indicates the floor of x, which is the largest
integer not greater than x.
The compiler uses the rules shown in Table 3-5 for aligning packed arrays.
Table 3-5. Size and Alignment of Pascal Packed Arrays
| Packed Arrays |
|
|---|---|---|
Scalar Type | Size | Alignment |
boolean | 8 | byte |
char | 8 | byte |
integer | 32 | word |
cardinal | 32 | word |
pointer | 32 | word |
file | 32 | word |
real | 32 | word |
double | 64 | doubleword |
subrange of: |
|
|
0..1 or -1..0 | 1 | bit |
0..3 or -2..1 | 2 | 2-bit |
0..15 or -8..7 | 4 | 4-bit |
0..255 or -128..127 | 8 | byte |
0..65535 or -32768..32767 | 16 | halfword |
0..232 - 1 |
|
|
-231..-231 - 1 | 32 | word |
set of char | 128 | word |
set of a..b | See note |
|
![]() | Note: For packed arrays, the compiler uses the minimum number of bits possible in creating the set of a..b. |
The following formula is used:
If (b - 32 ⌊a/32⌋ + 1 ) ≤ 32 then size = b - 32 \ξεβ a/32⌋ + 1 bits else size = ⌊b/32⌋ - \ξεβ a/32⌋ + 1 words |
Note that the set of a..b is aligned on an n-bit boundary where n is a power of 2. The value of n is computed as follows:
n = 2⌈log2(size)⌉ |
For example, the set of 0..2 has a size of 3 bits as computed above and will align on a 4-bit boundary.
See Section 3.4 at the end of this chapter for rules about specifying the upper and lower bounds of sets.
The compiler uses the rules shown in Table 3-6 for aligning packed records.
Table 3-6. Size and Alignment of Pascal Packed Records
| Packed Arrays |
|
|---|---|---|
Scalar Type | Size | Alignment |
boolean | 8 | byte |
char | 8 | byte |
integer | 32 | word |
cardinal | 32 | word |
pointer | 32 | word |
file | 32 | word |
real | 32 | word |
double | 64 | doubleword |
subrange of a..b | See note | bit/word |
![]() | Note: For packed records, the compiler uses the minimum number of bits possible in creating a subrange field. |
For the subrange a..b, this formula is used:
If a >= 0 then size = ⌈log2(b + 1) ⌉ bits |
If a > 0 then size = max(⌈log2(b + 1)⌉,⌈log2(-a ) ⌉)+1 bits |
The notation ⌈ x ⌉ indicates the ceiling of x, which is the smallest integer not less than x.
To avoid crossing a word boundary, the compiler moves data types aligned to bit boundaries in a packed record to the next word.
The maximum number of elements permitted in a set ranges between 481 and 512. This variance is due to the way Pascal implements sets. For efficient accessing of set elements, Pascal expects the lower-bound of a set to be a multiple of 32. If for the set specified:
set of a..b |
a is not a multiple of 32, Pascal adds elements to the set from a down to the next multiple of 32 less than a.
For example, the set:
set of 5..31 |
would have internal padding elements 0..4 added. These padding elements are inaccessible to the program. This implementation sacrifices some space for a fast, consistent method of accessing set elements.
The padding required to pad the lower bound down to a multiple of 32 varies between 0 and 31 elements.
For the set of a..b to be a valid set in Pascal, the following conditions must be met:
size = ( b - 32 ⌊a / 32⌋+ 1 ) < 512 |
Table 3-7 shows some example sets and whether each set is valid by the above equation.
Specification | Lower | Upper | Set Size | Valid Size |
|---|---|---|---|---|
set of 1..511 | 0 (padded down to value by Pascal) | 511 | 512 | Yes |
set of 0..511 | 0 | 511 | 512 | Yes |
set of 1..512 | 0* | 512 | 513 | No |
set of 31..512 | 0* | 512 | 513 | No |
set of 32..512 | 32 | 512 | 481 | Yes |
set of 32..543 | 32 | 543 | 512 | Yes |