14.4.6 Array of const

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.

The elements of the array of const are converted to a special variant record:

  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);  

Therefor, 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;  
  If High(Args)<0 then  
    Writeln (’No aguments’);  
  Writeln (’Got ’,High(Args)+1,’ arguments :’);  
  For i:=0 to High(Args) do  
    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);  
        Writeln (’(Unknown) : ’,args[i].vtype);  

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}  
  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’;  

Remark 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 QWord arguments in array of const. This is for Delphi compatibility, and the compiler will ignore any resulting range checks when in mode Delphi.