VarArgs

From Freepascal Amiga wiki
Jump to: navigation, search

VarArgs are used in those functions (usually system api library calls), that accepts a variable amount of values for a single parameter.

The SDK's of our beloved platforms usually declares two different functions when passing TagLists. One using a pointer to a taglist which contains a structure with (a variable amount of) values, and the other second declaration accepting the variable amount of values (directly) as single parameter.

VarArgs were (previously) declared:

  • on Amiga as Array of DWORD
  • on AROS as Array of Const
  • on MorphOS as Array of DWORD

Which, besides being inconsistent, resulted in quite some compiler related errors and/or warnings when attempting to write code that needs to be compiled for all these mentioned targets.

First of all: the Tags (and respective values) as declared inside SDK (for all platforms) should be of type LongWord, which is a problem given that array of const does not support LongWord's and generates compiler warnings because of that.

In order to workaround the array of const issues, all values stored in such array needed to be casted to LongInt.

Secondly, the array of DWord declaration has the issue of generating compiler warnings when attempting to store signed integers without the stored values being casted to unsigned integers.

When targeting all 3 platforms with the same source, this resulted in the need to cast both TagNames as well as TagValues to their corresponding underlying implementation (per platform).


Decision

In march 2016 it was decided (and implemented in Free Pascal 3.1.1 trunk) to change the declarations of library functions which accept a variable amount of parameters (so called VarArgs) from "Array of const" to "array of PtrUInt".

The reason behind that decision was fourfold:

  • Array of const dragged in unit ObjPas and therefor added a fair amount to the size of the executable
  • To have/create consistency amongst the platforms Amiga, AROS and MorphOS with regards to their VarArgs usage.
  • The chosen type PtrUInt is more future proof as it (automatically) takes f.e. 64 bit into consideration on compilation.
  • Functions and procedures which uses Array of const weren't allowed to be inlined (raised a compiler warning on certain targets and were not actually inlined), while array of PtrUInt allows this for the previously mentioned platforms.

!! As of Free Pascal revision 33260 (march 17th 2016) thou shall not use array of const when declaring VarTag library functions !!


Type PtrUInt

Type PtrUInt is described in the Free Pascal Manual here and mentions that this type is declared in unit System.

Furthermore, we can see that this type is declared as being a DWord(*), meaning it is an unsigned type.

(*) Dword, but with an exception: PtrUInt is an unsigned integer type which has always the same size as a pointer. When using integers which will be cast to pointers and vice versa, use this type, never the regular Cardinal type.

Therefore, the size of variables declared as PtrUInt will have a different size depending on the target platform (16-bit vs 32-bit vs 64-bit).


Usage

As for an example, let's take a look at the declaration of intuition library function OpenWindowTags().

declaration:

 function OpenWindowTags(newWindow: PNewWindow; tagList: array of PtrUInt): PWindow;


In order to call this function, we should use the following code:

 MyWindow := OpenWindowTags(nil, 
 [
   WA_Title, 'Close the Window to Quit',
   WA_..tagname.., ..tagvalue..
   TAG_END
 ])


Implications

The change from Array of Const to Array of PtrUInt should not really have important impact on your existing sources, except when you explicitly (pre)declared your varargs/taglist with already filled variables and attempt to pass that along such a function.

In that case, you should take note that such array declaration must now be of type PtrUInt (and not of type ULONG, SLONG or otherwise).

Another issue that might perhaps be encountered is the fact that (provided) TagNames and actual TagValues are now being interpreted as PtrUInt. (depending on the platform the source targets, this can raise compiler warnings and/or hints).

In case you were used to cast those tagnames/values as ULONG and/or SLONG, then now is the time to stop doing that (there is actually no need anymore), and instead use the special crafted (inline) function AsTag() (available inside unit Utility) that have overload versions for each type allowed inside such a taglist.

With the introduction of Array of PtrUInt as VarArgs, it was also decided to declare unit SystemVarTags for Amiga as being obsolete. All varargs related functions (previously declared inside unit SystemVarTags) now resides in their own corresponding units.


Examples

Calling a library function

Insert code here


(Pre)defining array values

Insert code here


Handling VarArgs manually

Insert code here