In Object Pascal or Delphi mode, Free Pascal supports the Array of Const construction to pass
parameters to a subroutine.
This is a special case of the Open array construction, where it is allowed to pass any expression in
an array to a function or procedure. The expression must have a simple result type: structures
cannot be passed as an argument. This means that all ordinal, float or string types can
be passed, as well as pointers, classes and interfaces (since the latter two are actually
pointers).
The elements of the array of const are converted to a special variant record:
Type
PVarRec = ^TVarRec;
TVarRec = record
case VType : Ptrint of
vtInteger : (VInteger: Longint);
vtBoolean : (VBoolean: Boolean);
vtChar : (VChar: Char);
vtWideChar : (VWideChar: WideChar);
vtExtended : (VExtended: PExtended);
vtString : (VString: PShortString);
vtPointer : (VPointer: Pointer);
vtPChar : (VPChar: PChar);
vtObject : (VObject: TObject);
vtClass : (VClass: TClass);
vtPWideChar : (VPWideChar: PWideChar);
vtAnsiString : (VAnsiString: Pointer);
vtCurrency : (VCurrency: PCurrency);
vtVariant : (VVariant: PVariant);
vtInterface : (VInterface: Pointer);
vtWideString : (VWideString: Pointer);
vtInt64 : (VInt64: PInt64);
vtQWord : (VQWord: PQWord);
end;
Therefore, inside the procedure body, the array of const argument is equivalent to an open array
of TVarRec:
Procedure Testit (Args: Array of const);
Var I : longint;
begin
If High(Args)<0 then
begin
Writeln (’No aguments’);
exit;
end;
Writeln (’Got ’,High(Args)+1,’ arguments :’);
For i:=0 to High(Args) do
begin
write (’Argument ’,i,’ has type ’);
case Args[i].vtype of
vtinteger :
Writeln (’Integer, Value :’,args[i].vinteger);
vtboolean :
Writeln (’Boolean, Value :’,args[i].vboolean);
vtchar :
Writeln (’Char, value : ’,args[i].vchar);
vtextended :
Writeln (’Extended, value : ’,args[i].VExtended^);
vtString :
Writeln (’ShortString, value :’,args[i].VString^);
vtPointer :
Writeln (’Pointer, value : ’,Longint(Args[i].VPointer));
vtPChar :
Writeln (’PChar, value : ’,Args[i].VPChar);
vtObject :
Writeln (’Object, name : ’,Args[i].VObject.Classname);
vtClass :
Writeln (’Class reference, name :’,Args[i].VClass.Classname);
vtAnsiString :
Writeln (’AnsiString, value :’,AnsiString(Args[I].VAnsiString);
else
Writeln (’(Unknown) : ’,args[i].vtype);
end;
end;
end;
In code, it is possible to pass an arbitrary array of elements to this procedure:
S:=’Ansistring 1’;
T:=’AnsiString 2’;
Testit ([]);
Testit ([1,2]);
Testit ([’A’,’B’]);
Testit ([TRUE,FALSE,TRUE]);
Testit ([’String’,’Another string’]);
Testit ([S,T]) ;
Testit ([P1,P2]);
Testit ([@testit,Nil]);
Testit ([ObjA,ObjB]);
Testit ([1.234,1.234]);
TestIt ([AClass]);
If the procedure is declared with the cdecl modifier, then the compiler will pass the array as a C
compiler would pass it. This, in effect, emulates the C construct of a variable number of arguments,
as the following example will show:
program testaocc;
{$mode objfpc}
Const
P : PChar = ’example’;
Fmt : PChar =
’This %s uses printf to print numbers (%d) and strings.’#10;
// Declaration of standard C function printf:
procedure printf (fm : pchar; args : array of const);cdecl; external ’c’;
begin
printf(Fmt,[P,123]);
end.
Remark Note that this is not true for Delphi, so code relying on this feature will not be portable.
Remark Note that there is no support for DWord (or cardinal) arguments in array of const. They are
converted to vtInteger/vtLongint. This is for Delphi compatibility, and the compiler will ignore
any resulting range checks when in mode Delphi.