10.3.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.

In the procedure, passed the arguments can be examined using a special record:

Type  
   PVarRec = ^TVarRec;  
   TVarRec = record  
     case VType : Longint of  
       vtInteger    : (VInteger: Longint);  
       vtBoolean    : (VBoolean: Boolean);  
       vtChar       : (VChar: Char);  
       vtExtended   : (VExtended: PExtended);  
       vtString     : (VString: PShortString);  
       vtPointer    : (VPointer: Pointer);  
       vtPChar      : (VPChar: PChar);  
       vtObject     : (VObject: TObject);  
       vtClass      : (VClass: TClass);  
       vtAnsiString : (VAnsiString: Pointer);  
       vtWideString : (VWideString: Pointer);  
       vtInt64      : (VInt64: PInt64);  
   end;

Inside the procedure body, the array of const 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].VAnsiStr  
    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 modier, then the compiler will pass the array as a C compiler would pass it. This, in eect, 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 that this is not true for Delphi, so code relying on this feature will not be portable.