Free Pascal supports fixed records and records with variant parts. The syntax diagram for a record type is
_________________________________________________________________________________________________________
Record types
____________________________________________
So the following are valid record type declarations:
Type Point = Record X,Y,Z : Real; end; RPoint = Record Case Boolean of False : (X,Y,Z : Real); True : (R,theta,phi : Real); end; BetterRPoint = Record Case UsePolar : Boolean of False : (X,Y,Z : Real); True : (R,theta,phi : Real); end;
The variant part must be last in the record. The optional identifier in the case statement serves to access the tag field value, which otherwise would be invisible to the programmer. It can be used to see which variant is active at a certain time3. In effect, it introduces a new field in the record.
Remark It is possible to nest variant parts, as in:
Type MyRec = Record X : Longint; Case byte of 2 : (Y : Longint; case byte of 3 : (Z : Longint); ); end;
When initializing a variable (or constant) of type record, a special syntax must be used: for each field in the record, the name must be specified, followed by a colon and an expression for the field value. The compiler must be able to evaluate the expression at compile time. The values of the field are separated by a semicolon.
_________________________________________________________________________________________________________
Constant record value
____________________________________________
For the MyRec record above, the following would initialize all fields:
var R : MyRec = (X : 1; Y: 2; Z: 3);
You do not need to specify values for all fields, but then the compiler will warn you. The following is a valid initialization:
var R : MyRec = (X : 1; Y: 2);
But it results in a warning:
cr.pp(11,26) Warning: Some fields coming after "Y" were not initialized
The layout and size of a record is influenced by five aspects:
The size of its fields.
The alignment requirements of the types of the fields, which are platform-dependent. Note that the alignment requirements of a type inside a record may be different from those of a separate variable of that type. Additionally, the location of a field inside a record may also influence its type’s alignment requirements.
The currently active {$ALIGN N} or {$PACKRECORDS N} setting (these settings override each other, so the last one specified is the active one; note that these directives do not accept exactly the same arguments, see the programmer’s manual for more information).
The currently active {$CODEALIGN RECORDMIN=X} setting.
The currently active {$CODEALIGN RECORDMAX=X} setting.
The layout and size of variant parts in records is determined by replacing them with a field whose type is a record with as first element a field of the tag field type if an identifier was declared for this tag field, followed by the elements of the biggest variant.
Field F2’s offset in a record is equal to the sum of the previous field F1’s offset and F1’s size, rounded up to a multiple of F2’s required alignment. This required alignment is calculated as follows:
The required alignment is set to the default alignment of the field’s type, possibly adjusted based on the fact that this type occurs in a record and on the field’s location in the record.
If the required alignment is smaller than the currently active {$CODEALIGN RECORDMIN=X} setting, it is changed to this X value.
If the currently active {$ALIGN N} or {$PACKRECORDS N} setting is
a numerical value: if the required alignment is larger than N, it is changed to N. I. e., if N is 1, all fields will be placed right after each other.
RESET or DEFAULT: the resulting required alignment is target dependent.
C: the required alignment is adjusted according to the rules specified in the official ABI for the current platform.
POWER/POWERPC, MAC68K: the alignment value’s adjustment is determined by following the official ABI rules for resp. the (Classic) Macintosh PowerPC or Macintosh 680x0 platforms.
The size of a record is equal to the sum of the record’s last field’s offset and this field’s size, rounded up to a multiple of the record’s required alignment. The record’s required alignment is calculated as follows:
The required alignment is set to the alignment of the record’s field with the largest alignment, as determined while laying out the record.
If the current {$ALIGN N} or {$PACKRECORDS N} setting is different from C and the required alignment is larger than than the currently active {$CODEALIGN RECORDMAX=X}, the required alignment is changed to X.
If the current {$ALIGN N} or {$PACKRECORDS N} setting is equal to C, the required alignment is determined by following the official ABI rules.
Free Pascal also supports a “packed record”, which is a record where all the elements are byte-aligned. As a result, the two following declarations are equivalent:
{$PackRecords 1} Trec2 = Record A : Byte; B : Word; end; {$PackRecords default}
and
Trec2 = Packed Record A : Byte; B : Word; end;
Note the {$PackRecords Default} after the first declaration to restore the default setting!
Given the platform-dependent nature of how records are laid out in memory, the only way to ensure a compatible layout across platforms (assuming that all fields are declared using a type with the same meaning across these same platforms) is by using {$PACKRECORDS 1}.
In particular, if a typed file with records, produced by a Turbo Pascal program, must be read, then chances are that attempting to read that file correctly will fail. The reason is that Free Pascal’s default {$PACKRECORDS N} setting is not necessarily compatible with Turbo Pascal’s. It can be changed to {$PACKRECORDS 1} or {$PACKRECORDS 2} depending on the setting used in the Turbo Pascal program that create the file (although it may still fail with {$PACKRECORDS 2} due to different type alignment requirements between 16 bit MSDOS and your current platform).
The same remark goes for Delphi: exchanging data is only guaranteed to be possible if both the producer and consumer use a packed record, or if they are on the same platform and use the same {$PACKRECORDS X} setting.
3However, it is up to the programmer to maintain this field.