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 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 that this is not true for Delphi, so code relying on this feature will not be portable.