Subsections

- 1 Base types
  - 1 Ordinal types
  - 2 Real types
- 2 Character types
  - 1 Char
  - 2 Strings
  - 3 Short strings
  - 4 Ansistrings
  - 5 Constant strings
  - 6 PChar
- 3 Structured Types
  - 1 Arrays
  - 2 Record types
  - 3 Set types
  - 4 File types
- 4 Pointers
- 5 Procedural types

# 3 Types

All variables have a type. Free Pascal supports the same basic types as Turbo Pascal, with some extra types from Delphi. The programmer can declare his own types, which is in essence defining an identifier that can be used to denote this custom type when declaring variables further in the source code.

> Type declaration

There are 7 major type classes :

> Types

The last class, type identifier, is just a means to give another name to a type. This presents a way to make types platform independent, by only using these types, and then defining these types for each platform individually. The programmer that uses these units doesn't have to worry about type size and so on. It also allows to use shortcut names for fully qualified type names. e.g. define `system.longint` as `Olongint` and then redefine `longint`.

# 1 Base types

The base or simple types of Free Pascal are the Delphi types. We will discuss each separate.

> Simple types

## 1 Ordinal types

With the exception of Real types, all base types are ordinal types. Ordinal types have the following characteristics:

1. Ordinal types are countable and ordered, i.e. it is, in principle, possible to start counting them one bye one, in a specified order. This property allows the operation of functions as Inc, Ord, Dec on ordinal types to be defined.
2. Ordinal values have a smallest possible value. Trying to apply the Pred function on the smallest possible value will generate a range check error if range checking is enabled.
3. Ordinal values have a largest possible value. Trying to apply the Succ function on the largest possible value will generate a range check error if range checking is enabled.

### 1 Integers

A list of pre-defined ordinal types is presented in table (ordinals)

Table: Predefined ordinal types
Name
Integer
Shortint
SmallInt
Longint
Int64
Byte
Word
Cardinal
QWord
Boolean
ByteBool
LongBool
Char

The integer types, and their ranges and sizes, that are predefined in Free Pascal are listed in table (integers) .

Table: Predefined integer types
Type | Range | Size in bytes
Byte | 0 .. 255 | 1
Shortint | -128 .. 127 | 1
Smallint | -32768 .. 32767 | 2
Integer | either smallint, longint or int64 | size 2,4 or 8
Word | 0 .. 65535 | 2
Longint | -2147483648 .. 2147483647 | 4
Cardinal | 0..4294967295 | 4
Int64 | -9223372036854775808 .. 9223372036854775807 | 8
QWord | 0 .. 18446744073709551615 | 8

The `integer` type maps to the smallint type in the default Free Pascal mode. It maps to either a longint or int64 in either Delphi or ObjFPC mode. This is summarized in table (integer32type) for 32-bit processors (such as Intel 80x86, Motorola 680x0, PowerPC 32-bit, SPARC v7, MIPS32), and in table (integer64type) for 64-bit processors (such as Alpha AXP, SPARC v9 or later, Intel Itanium, MIPS64).

Table: `Integer` type mapping for 32-bit processors
Compiler mode | Range | Size in bytes
<default> | -32768 .. 32767 | 2
tp | -32768 .. 32767 | 2
Delphi | -2147483648 .. 2147483647 | 4
ObjFPC | -2147483648 .. 2147483647 | 4

Table: `Integer` type mapping for 64-bit processors
Compiler mode | Range | Size in bytes
<default> | -32768 .. 32767 | 2
tp | -32768 .. 32767 | 2
Delphi | -9223372036854775808 .. 9223372036854775807 | 8
ObjFPC | -9223372036854775808 .. 9223372036854775807 | 8

Free Pascal does automatic type conversion in expressions where different kinds of integer types are used.

### 2 Boolean types

Free Pascal supports the `Boolean` type, with its two pre-defined possible values `True` and `False`. It also supports the `ByteBool`, `WordBool` and `LongBool` types. These are the only two values that can be assigned to a `Boolean` type. Of course, any expression that resolves to a `boolean` value, can also be assigned to a boolean type.

Table: Boolean types
Name | Size | Ord(True)
Boolean | 1 | 1
ByteBool | 1 | Any nonzero value
WordBool | 2 | Any nonzero value
LongBool | 4 | Any nonzero value

Assuming `B` to be of type `Boolean`, the following are valid assignments:

     B := True;
     B := False;
     B := 1<>2;  { Results in B := True }

Boolean expressions are also used in conditions.

Remark: In Free Pascal, boolean expressions are always evaluated in such a way that when the result is known, the rest of the expression will no longer be evaluated (Called short-cut evaluation). In the following example, the function `Func` will never be called, which may have strange side-effects.

     ...
     B := False;
     A := B and Func;

Here `Func` is a function which returns a `Boolean` type.

### 3 Enumeration types

Enumeration types are supported in Free Pascal. On top of the Turbo Pascal implementation, Free Pascal allows also a C-style extension of the enumeration type, where a value is assigned to a particular element of the enumeration list.

> Enumerated types

(see chapter Expressions for how to use expressions) When using assigned enumerated types, the assigned elements must be in ascending numerical order in the list, or the compiler will complain. The expressions used in assigned enumerated elements must be known at compile time. So the following is a correct enumerated type declaration:

    Type
      Direction = ( North, East, South, West );

The C style enumeration type looks as follows:

    Type
      EnumType = (one, two, three, forty := 40,fortyone);

As a result, the ordinal number of `forty` is `40`, and not `3`, as it would be when the `':= 40'` wasn't present. The ordinal value of `fortyone` is then 41, and not `4`, as it would be when the assignment wasn't present. After an assignment in an enumerated definition the compiler adds 1 to the assigned value to assign to the next enumerated value. When specifying such an enumeration type, it is important to keep in mind that the enumerated elements should be kept in ascending order. The following will produce a compiler error:

    Type
      EnumType = (one, two, three, forty := 40, thirty := 30);

It is necessary to keep `forty` and `thirty` in the correct order. When using enumeration types it is important to keep the following points in mind:

1. The `Pred` and `Succ` functions cannot be used on this kind of enumeration types. Trying to do this anyhow will result in a compiler error.
2. Enumeration types stored using a default size. This behaviour can be changed with the `{$PACKENUM n}` compiler directive, which tells the compiler the minimal number of bytes to be used for enumeration types. For instance

       Type
       {$PACKENUM 4}
         LargeEnum = ( BigOne, BigTwo, BigThree );
       {$PACKENUM 1}
         SmallEnum = ( one, two, three );
       Var S : SmallEnum;
           L : LargeEnum;
       begin
         WriteLn ('Small enum : ',SizeOf(S));
         WriteLn ('Large enum : ',SizeOf(L));
       end.

   will, when run, print the following:

       Small enum : 1
       Large enum : 4

More information can be found in the Programmers' guide, in the compiler directives section.

### 4 Subrange types

A subrange type is a range of values from an ordinal type (the host type). To define a subrange type, one must specify it's limiting values: the highest and lowest value of the type.

> Subrange types

Some of the predefined `integer` types are defined as subrange types:

    Type
      Longint  = $80000000..$7fffffff;
      Integer  = -32768..32767;
      shortint = -128..127;
      byte     = 0..255;
      Word     = 0..65535;

Subrange types of enumeration types can also be defined:

    Type
      Days = (monday,tuesday,wednesday,thursday,friday,
              saturday,sunday);
      WorkDays = monday .. friday;
      WeekEnd = Saturday .. Sunday;

## 2 Real types

Free Pascal uses the math coprocessor (or emulation) for all its floating-point calculations. The Real native type is processor dependant, but it is either Single or Double. Only the IEEE floating point types are supported, and these depend on the target processor and emulation options. The true Turbo Pascal compatible types are listed in table (Reals) .

Table: Supported Real types
Type | Range | Significant digits | Size
Real | platform dependant | ??? | 4 or 8
Single | 1.5E-45 .. 3.4E38 | 7-8 | 4
Double | 5.0E-324 .. 1.7E308 | 15-16 | 8
Extended | 1.9E-4951 .. 1.1E4932 | 19-20 | 10
Comp | -2E64+1 .. 2E63-1 | 19-20 | 8

The `Comp` type is, in effect, a 64-bit integer and is not available on all target platforms. To get more information on the supported types for each platform, refer to the Programmers' guide.

# 2 Character types

## 1 Char

Free Pascal supports the type `Char`. A `Char` is exactly 1 byte in size, and contains one character. A character constant can be specified by enclosing the character in single quotes, as follows : 'a' or 'A' are both character constants. A character can also be specified by its ASCII value, by preceding the ASCII value with the number symbol (#). For example specifying `#65` would be the same as `'A'`. Also, the caret character (`^`) can be used in combination with a letter to specify a character with ASCII value less than 27. Thus `^G` equals `#7` (G is the seventh letter in the alphabet.) When the single quote character must be represented, it should be typed two times successively, thus `''''` represents the single quote character.

## 2 Strings

Free Pascal supports the `String` type as it is defined in Turbo Pascal (A sequence of characters with a specified length) and it supports ansistrings as in Delphi. To declare a variable as a string, use the following type specification:

> ShortString

The meaning of a string declaration statement is interpreted differently depending on the `{$H}` switch. The above declaration can declare an ansistrng or a short string.

Whatever the actual type, ansistrings and short strings can be used interchangeably. The compiler always takes care of the necessary type conversions. Note, however, that the result of an expression that contains ansistrings and short strings will always be an ansistring.

## 3 Short strings

A string declaration declares a short string in the following cases:

1. If the switch is off: `{$H-}`, the string declaration will always be a short string declaration.
2. If the switch is on `{$H+}`, and there is a length specifier, the declaration is a short string declaration.

The predefined type `ShortString` is defined as a string of length 255:

     ShortString = String[255];

If the size of the string is not specified, `255` is taken as a default. The length of the string can be obtained with the Length standard runtime routine. For example in

    {$H-}

    Type
       NameString = String[10];
       StreetString = String;

`NameString` can contain a maximum of 10 characters. While `StreetString` can contain up to 255 characters.

## 4 Ansistrings

If the `{$H}` switch is on, then a string definition that doesn't contain a length specifier, will be regarded as an ansistring.

Ansistrings are strings that have no length limit. They are reference counted. Internally, an ansistring is treated as a pointer.

If the string is empty (`''`), then the pointer is nil. If the string is not empty, then the pointer points to a structure in heap memory.

It is possible to typecast an ansistring to a pchar. If the string is empty (so the pointer is nil) then the compiler makes sure that the typecasted pchar will point to a null byte. AnsiStrings can be unlimited in length.

Assigning one ansistring to another doesn't involve moving the actual string. A statement

      S2:=S1;

results in the reference count of `S2` being decreased by one, The referece count of `S1` is increased by one, and finally `S1` (as a pointer) is copied to `S2`. This is a significant speed-up in the code.

If a reference count reaches zero, then the memory occupied by the string is deallocated automatically, so no memory leaks arise.

When an ansistring is declared, the Free Pascal compiler initially allocates just memory for a pointer, not more. This pointer is guaranteed to be nil, meaning that the string is initially empty. This is true for local, global or part of a structure (arrays, records or objects).

This does introduce an overhead. For instance, declaring

    Var
      A : Array[1..100000] of string;

Will copy 100,000 times `nil` into `A`. When `A` goes out of scope, then the 100,000 strings will be dereferenced one by one. All this happens invisibly for the programmer, but when considering performance issues, this is important.

Memory will be allocated only when the string is assigned a value. If the string goes out of scope, then it is automatically dereferenced.

If a value is assigned to a character of a string that has a reference count greater than 1, such as in the following statements:

      S:=T;  { reference count for S and T is now 2 }
      S[I]:='@';

then a copy of the string is created before the assignment. This is known as copy-on-write semantics.

The Length function must be used to get the length of an ansistring.

To set the length of an ansistring, the SetLength function must be used. Constant ansistrings have a reference count of -1 and are treated specially.

Ansistrings are converted to short strings by the compiler if needed, this means that the use of ansistrings and short strings can be mixed without problems.

Ansistrings can be typecasted to `PChar` or `Pointer` types:

    Var P : Pointer;
        PC : PChar;
        S : AnsiString;

    begin
      S :='This is an ansistring';
      PC:=Pchar(S);
      P :=Pointer(S);

There is a difference between the two typecasts. When an empty ansistring is typecasted to a pointer, the pointer wil be `Nil`. If an empty ansistring is typecasted to a `PChar`, then the result will be a pointer to a zero byte (an empty string).

The result of such a typecast must be used with care. In general, it is best to consider the result of such a typecast as read-only, i.e. suitable for passing to a procedure that needs a constant pchar argument.

It is therefore NOT advisable to typecast one of the following:

1. expressions.
2. strings that have reference count larger than 0. (call uniquestring to ensure a string has reference count 1)

## 5 Constant strings

To specify a constant string, it must be enclosed in single-quotes, just as a `Char` type, only now more than one character is allowed. Given that `S` is of type `String`, the following are valid assignments:

    S := 'This is a string.';
    S := 'One'+', Two'+', Three';
    S := 'This isn''t difficult !';
    S := 'This is a weird character : '#145' !';

As can be seen, the single quote character is represented by 2 single-quote characters next to each other. Strange characters can be specified by their ASCII value. The example shows also that two strings can be added. The resulting string is just the concatenation of the first with the second string, without spaces in between them. Strings can not be substracted, however.

Whether the constant string is stored as an ansistring or a short string depends on the settings of the `{$H}` switch.

## 6 PChar

Free Pascal supports the Delphi implementation of the `PChar` type. `PChar` is defined as a pointer to a `Char` type, but allows additional operations. The `PChar` type can be understood best as the Pascal equivalent of a C-style null-terminated string, i.e. a variable of type `PChar` is a pointer that points to an array of type `Char`, which is ended by a null-character (`#0`). Free Pascal supports initializing of `PChar` typed constants, or a direct assignment. For example, the following pieces of code are equivalent:

    program one;
    var p : PChar;
    begin
      P := 'This is a null-terminated string.';
      WriteLn (P);
    end.

Results in the same as

    program two;
    const P : PChar = 'This is a null-terminated string.'
    begin
      WriteLn (P);
    end.

These examples also show that it is possible to write the contents of the string to a file of type `Text`. The strings unit contains procedures and functions that manipulate the `PChar` type as in the standard C library. Since it is equivalent to a pointer to a type `Char` variable, it is also possible to do the following:

    Program three;
    Var S : String[30];
        P : PChar;
    begin
      S := 'This is a null-terminated string.'#0;
      P := @S[1];
      WriteLn (P);
    end.

This will have the same result as the previous two examples. Null-terminated strings cannot be added as normal Pascal strings. If two `PChar` strings mustt be concatenated; the functions from the unit strings must be used.

However, it is possible to do some pointer arithmetic. The operators `+` and `-` can be used to do operations on `PChar` pointers. In table (PCharMath) , `P` and `Q` are of type `PChar`, and `I` is of type `Longint`.

Table: `PChar` pointer arithmetic
Operation | Result
`P + I` | Adds `I` to the address pointed to by `P`.
`I + P` | Adds `I` to the address pointed to by `P`.
`P - I` | Substracts `I` from the address pointed to by `P`.
`P - Q` | Returns, as an integer, the distance between 2 addresses
| (or the number of characters between `P` and `Q`)

# 3 Structured Types

A structured type is a type that can hold multiple values in one variable. Stuctured types can be nested to unlimited levels.

> Structured Types

Unlike Delphi, Free Pascal does not support the keyword `Packed` for all structured types, as can be seen in the syntax diagram. It will be mentioned when a type supports the `packed` keyword. In the following, each of the possible structured types is discussed.

## 1 Arrays

Free Pascal supports arrays as in Turbo Pascal, multi-dimensional arrays and packed arrays are also supported:

> Array types

The following is a valid array declaration:

    Type
      RealArray = Array [1..100] of Real;

As in Turbo Pascal, if the array component type is in itself an array, it is possible to combine the two arrays into one multi-dimensional array. The following declaration:

    Type
       APoints = array[1..100] of Array[1..3] of Real;

is equivalent to the following declaration:

    Type
       APoints = array[1..100,1..3] of Real;

The functions High and Low return the high and low bounds of the leftmost index type of the array. In the above case, this would be 100 and 1.

## 2 Record types

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 types 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 time. 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;

The size of a record is the sum of the sizes of its fields, each size of a field is rounded up to a power of two. If the record contains a variant part, the size of the variant part is the size of the biggest variant, plus the size of the tag field type if an identifier was declared for it. Here also, the size of each part is first rounded up to two. So in the above example, SizeOf would return 24 for `Point`, 24 for `RPoint` and 26 for `BetterRPoint`. For `MyRec`, the value would be 12. 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 for this is that by default, elements of a record are aligned at 2-byte boundaries, for performance reasons. This default behaviour can be changed with the `{$PackRecords n}` switch. Possible values for `n` are 1, 2, 4, 16 or `Default`. This switch tells the compiler to align elements of a record or object or class that have size larger than `n` on `n` byte boundaries. Elements that have size smaller or equal than `n` are aligned on natural boundaries, i.e. to the first power of two that is larger than or equal to the size of the record element. The keyword `Default` selects the default value for the platform that the code is compiled for (currently, this is 2 on all platforms) Take a look at the following program:

    Program PackRecordsDemo;
    type
       {$PackRecords 2}
         Trec1 = Record
           A : byte;
           B : Word;
         end;

         {$PackRecords 1}
         Trec2 = Record
           A : Byte;
           B : Word;
           end;
       {$PackRecords 2}
         Trec3 = Record
           A,B : byte;
         end;

        {$PackRecords 1}
         Trec4 = Record
           A,B : Byte;
           end;
       {$PackRecords 4}
         Trec5 = Record
           A : Byte;
           B : Array[1..3] of byte;
           C : byte;
         end;

         {$PackRecords 8}
         Trec6 = Record
           A : Byte;
           B : Array[1..3] of byte;
           C : byte;
           end;
       {$PackRecords 4}
         Trec7 = Record
           A : Byte;
           B : Array[1..7] of byte;
           C : byte;
         end;

         {$PackRecords 8}
         Trec8 = Record
           A : Byte;
           B : Array[1..7] of byte;
           C : byte;
           end;
    Var rec1 : Trec1;
        rec2 : Trec2;
        rec3 : TRec3;
        rec4 : TRec4;
        rec5 : Trec5;
        rec6 : TRec6;
        rec7 : TRec7;
        rec8 : TRec8;

    begin
      Write ('Size Trec1 : ',SizeOf(Trec1));
      Writeln (' Offset B : ',Longint(@rec1.B)-Longint(@rec1));
      Write ('Size Trec2 : ',SizeOf(Trec2));
      Writeln (' Offset B : ',Longint(@rec2.B)-Longint(@rec2));
      Write ('Size Trec3 : ',SizeOf(Trec3));
      Writeln (' Offset B : ',Longint(@rec3.B)-Longint(@rec3));
      Write ('Size Trec4 : ',SizeOf(Trec4));
      Writeln (' Offset B : ',Longint(@rec4.B)-Longint(@rec4));
      Write ('Size Trec5 : ',SizeOf(Trec5));
      Writeln (' Offset B : ',Longint(@rec5.B)-Longint(@rec5),
               ' Offset C : ',Longint(@rec5.C)-Longint(@rec5));
      Write ('Size Trec6 : ',SizeOf(Trec6));
      Writeln (' Offset B : ',Longint(@rec6.B)-Longint(@rec6),
               ' Offset C : ',Longint(@rec6.C)-Longint(@rec6));
      Write ('Size Trec7 : ',SizeOf(Trec7));
      Writeln (' Offset B : ',Longint(@rec7.B)-Longint(@rec7),
               ' Offset C : ',Longint(@rec7.C)-Longint(@rec7));
      Write ('Size Trec8 : ',SizeOf(Trec8));
      Writeln (' Offset B : ',Longint(@rec8.B)-Longint(@rec8),
               ' Offset C : ',Longint(@rec8.C)-Longint(@rec8));
    end.

The output of this program will be :

    Size Trec1 : 4 Offset B : 2
    Size Trec2 : 3 Offset B : 1
    Size Trec3 : 2 Offset B : 1
    Size Trec4 : 2 Offset B : 1
    Size Trec5 : 8 Offset B : 4 Offset C : 7
    Size Trec6 : 8 Offset B : 4 Offset C : 7
    Size Trec7 : 12 Offset B : 4 Offset C : 11
    Size Trec8 : 16 Offset B : 8 Offset C : 15

And this is as expected. In `Trec1`, since `B` has size 2, it is aligned on a 2 byte boundary, thus leaving an empty byte between `A` and `B`, and making the total size 4. In `Trec2`, `B` is aligned on a 1-byte boundary, right after `A`, hence, the total size of the record is 3. For `Trec3`, the sizes of `A,B` are 1, and hence they are aligned on 1 byte boundaries. The same is true for `Trec4`. For `Trec5`, since the size of B - 3 - is smaller than 4, `B` will be on a 4-byte boundary, as this is the first power of two that is larger than it's size. The same holds for `Trec6`. For `Trec7`, `B` is aligned on a 4 byte boundary, since it's size - 7 - is larger than 4. However, in `Trec8`, it is aligned on a 8-byte boundary, since 8 is the first power of two that is greater than 7, thus making the total size of the record 16. Free Pascal supports also the 'packed record', this is a record where all the elements are byte-aligned. Thus the two following declarations are equivalent:

         {$PackRecords 1}
         Trec2 = Record
           A : Byte;
           B : Word;
           end;
         {$PackRecords 2}

and

         Trec2 = Packed Record
           A : Byte;
           B : Word;
           end;

Note the `{$PackRecords 2}` after the first declaration !

## 3 Set types

Free Pascal supports the set types as in Turbo Pascal. The prototype of a set declaration is:

> Set Types

Each of the elements of `SetType` must be of type `TargetType`. `TargetType` can be any ordinal type with a range between `0` and `255`. A set can contain maximally `255` elements. The following are valid set declaration:

    Type
        Junk = Set of Char;

        Days = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
        WorkDays : Set of days;

Given this set declarations, the following assignment is legal:

    WorkDays := [ Mon, Tue, Wed, Thu, Fri];

The operators and functions for manipulations of sets are listed in table (SetOps) .

Table: Set Manipulation operators
Operation | Operator
Union | +
Difference | -
Intersection | *
Add element | `include`
Delete element | `exclude`

Two sets can be compared with the `<>` and `=` operators, but not (yet) with the `<` and `>` operators. The compiler stores small sets (less than 32 elements) in a Longint, if the type range allows it. This allows for faster processing and decreases program size. Otherwise, sets are stored in 32 bytes.

## 4 File types

File types are types that store a sequence of some base type, which can be any type except another file type. It can contain (in principle) an infinite number of elements. File types are used commonly to store data on disk. Nothing prevents the programmer, however, from writing a file driver that stores it's data in memory. Here is the type declaration for a file type:

> File types

If no type identifier is given, then the file is an untyped file; it can be considered as equivalent to a file of bytes. Untyped files require special commands to act on them (see Blockread, Blockwrite). The following declaration declares a file of records:

    Type
       Point = Record
         X,Y,Z : real;
         end;
       PointFile = File of Point;

Internally, files are represented by the `FileRec` record, which is declared in the DOS unit.

A special file type is the `Text` file type, represented by the `TextRec` record. A file of type `Text` uses special input-output routines.

# 4 Pointers

Free Pascal supports the use of pointers. A variable of the pointer type contains an address in memory, where the data of another variable may be stored.

> Pointer types

As can be seen from this diagram, pointers are typed, which means that they point to a particular kind of data. The type of this data must be known at compile time. Dereferencing the pointer (denoted by adding `^` after the variable name) behaves then like a variable. This variable has the type declared in the pointer declaration, and the variable is stored in the address that is pointed to by the pointer variable. Consider the following example:

    Program pointers;
    type
      Buffer = String[255];
      BufPtr = ^Buffer;
    Var B  : Buffer;
        BP : BufPtr;
        PP : Pointer;
    etc..

In this example, `BP` is a pointer to a `Buffer` type; while `B` is a variable of type `Buffer`. `B` takes 256 bytes memory, and `BP` only takes 4 bytes of memory (enough to keep an adress in memory).

Remark: Free Pascal treats pointers much the same way as C does. This means that a pointer to some type can be treated as being an array of this type. The pointer then points to the zeroeth element of this array. Thus the following pointer declaration

    Var p : ^Longint;

Can be considered equivalent to the following array declaration:

    Var p : array[0..Infinity] of Longint;

The difference is that the former declaration allocates memory for the pointer only (not for the array), and the second declaration allocates memory for the entire array. If the former is used, the memory must be allocated manually, using the Getmem function. The reference `P^` is then the same as `p[0]`. The following program illustrates this maybe more clear:

    program PointerArray;
    var i : Longint;
        p : ^Longint;
        pp : array[0..100] of Longint;
    begin
      for i := 0 to 100 do pp[i] := i; { Fill array }
      p := @pp[0];                     { Let p point to pp }
      for i := 0 to 100 do
        if p[i]<>pp[i] then
          WriteLn ('Ohoh, problem !')
    end.

Free Pascal supports pointer arithmetic as C does. This means that, if `P` is a typed pointer, the instructions

    Inc(P);
    Dec(P);

Will increase, respectively decrease the address the pointer points to with the size of the type `P` is a pointer to. For example

    Var P : ^Longint;
    ...
     Inc (p);

will increase `P` with 4. Normal arithmetic operators on pointers can also be used, that is, the following are valid pointer arithmetic operations:

    var  p1,p2 : ^Longint;
         L : Longint;
    begin
      P1 := @P2;
      P2 := @L;
      L := P1-P2;
      P1 := P1-4;
      P2 := P2+4;
    end.

Here, the value that is added or substracted is not multiplied by the size of the type the pointer points to.

# 5 Procedural types

Free Pascal has support for procedural types, although it differs a little from the Turbo Pascal implementation of them. The type declaration remains the same, as can be seen in the following syntax diagram:

> Procedural types

For a description of formal parameter lists, see chapter Procedures. The two following examples are valid type declarations:

    Type TOneArg = Procedure (Var X : integer);
         TNoArg = Function : Real;
    var proc : TOneArg;
        func : TNoArg;

One can assign the following values to a procedural type variable:

1. `Nil`, for both normal procedure pointers and method pointers.
2. A variable reference of a procedural type, i.e. another variable of the same type.
3. A global procedure or function address, with matching function or procedure header and calling convention.
4. A method address.

Given these declarations, the following assignments are valid:

    Procedure printit (Var X : Integer);
    begin
      WriteLn (x);
    end;
    ...
    Proc := @printit;
    Func := @Pi;

From this example, the difference with Turbo Pascal is clear: In Turbo Pascal it isn't necessary to use the address operator (`@`) when assigning a procedural type variable, whereas in Free Pascal it is required (unless the `-So` switch is used, in which case the address operator can be dropped.)

Remark: The modifiers concerning the calling conventions must be the same as the declaration; i.e. the following code would give an error:

    Type TOneArgCcall = Procedure (Var X : integer);cdecl;
    var proc : TOneArgCcall;
    Procedure printit (Var X : Integer);
    begin
      WriteLn (x);
    end;
    begin
    Proc := @printit;
    end.

Because the `TOneArgCcall` type is a procedure that uses the cdecl calling convention.