Mega Code Archive

 
Categories / Delphi / Examples
 

Varargs

Subject: Delphi: Example of variable number of parameters program VarPar; { A simple program to demonstrate use of type-safe variable number of parameters in Delphi. Written Mars 1995 by Hallvard Vassbotn hallvard@falcon.no } uses WinCrt, SysUtils; { These are predefined in System: const vtInteger = 0; vtBoolean = 1; vtChar = 2; vtExtended = 3; vtString = 4; vtPointer = 5; vtPChar = 6; vtObject = 7; vtClass = 8; type TVarRec = record case Integer of vtInteger: (VInteger: Longint; VType: Byte); vtBoolean: (VBoolean: Boolean); vtChar: (VChar: Char); vtExtended: (VExtended: PExtended); vtString: (VString: PString); vtPointer: (VPointer: Pointer); vtPChar: (VPChar: PChar); vtObject: (VObject: TObject); vtClass: (VClass: TClass); end; } const TypeNames : array [vtInteger..vtClass] of PChar = ('Integer', 'Boolean', 'Char', 'Extended', 'String', 'Pointer', 'PChar', 'Object', 'Class'); { According to the on-line docs (search for TVarRec), array of const parameters are treated like array of TVarRec by the compiler. This example will work just as well if you change the declaration of TestMultiPar to: procedure TestMultiPar(const Args: array of TVarRec); This would make the implementation of the routine cleaner (no absolute variable declaration), but the interface would be less understandable to the user of the routine. The compiler looks at the parameters and builds the array directly on the stack. For each item in the array it also sets the VType field to one of the pre-defined constants vtXXXX. The actual value is always sent as four bytes of information. For the Boolean and Char types, only the first byte contains useful information. So, go ahead, now you can write all those neat routines with variable number of parameters - and still keep the type safety! } function PtrToHex(P: pointer): string; begin Result := IntToHex(Seg(P^), 4) + ':' + IntToHex(Ofs(P^), 4); end; procedure TestMultiPar(const Args: array of const); var ArgsTyped : array [0..$fff0 div sizeof(TVarRec)] of TVarRec absolute Args; i : integer; begin for i := Low(Args) to High(Args) do with ArgsTyped[i] do begin Write('Args[', i, '] : ', TypeNames[VType], ' = '); case VType of vtInteger: writeln(VInteger); vtBoolean: writeln(VBoolean); vtChar: writeln(VChar); vtExtended: writeln(VExtended^:0:4); vtString: writeln(VString^); vtPointer: writeln(PtrToHex(VPointer)); vtPChar: writeln(VPChar); vtObject: writeln(PtrToHex(Pointer(VObject))); vtClass: writeln(PtrToHex(Pointer(VClass))); end; end; end; var MyObj : TObject; begin Writeln('Test of type-safe variable number of parameters in Delphi:'); MyObj := TObject.Create; TestMultiPar([123, 45.67, PChar('ASCIIZ'), 'Hello, world!', true, 'X', @ShortDayNames, TObject, MyObj]); MyObj.Free; { To verify that the type-safety is used in the supplied formatting routines, try this: } writeln(Format('%d', ['hi'])); { The supplied parameter is not of the type expected. The '%d' format string signals that the parameter should be an integer value, but instead we send a string. At run-time this will generate a exception, and if you have enabled IDE-trapping of exceptions, Delphi will show you the offending line. Using c-type sprintf funtions like this will result in undefined behaviour (read: system crash, GP or whatever) } end. -- Hallvard Vassbotn | Falcon AS (a Reuters company) | Without programmers, hallvard@falcon.no | Stranden 1, 0250 OSLO, Norway | the world would stop!