the idea to implement C functions with a variable number of parameter is to use something like this :
Code: Select all
your_function(char* string, ...)
{
}
In C, when you have, say three parameters, like in
the parameters are pushed on the stack with the first argument pushed last, so that the first to be popped will be the first argument (I don't know if I explained it correctly).
In the case of ... arguments, you have to find the address of the next parameter you want, and you know that it's on the stack.
But 'string' is also on the stack, and you can get its address by '&string'. The second argument of the function will be at '&string + sizeof(string)'. lets this address be 'A'.
The third argument will be at 'A + sizeof(parameter at A)', etc...
va_start is usally a macro which takes the first argument of the function as parameter and returns the address where it can be found.
then, each time you retrieve an argument, you also have to call va_arg (IIRC), which takes the 'list pointer' and an integer as parameter, mostly given with a 'sizeof()' or even a type and increments the 'list pointer' with the integer (possibly rounded to fit stack element size).
Example :
Code: Select all
void f(char* string, ...)
{
va_list list_pointer;
int i;
va_start(list_pointer, string);
/* Do whatever you have to do */
/* Now you want to retrieve the second argument, which should be an int (you know it, because of the %d or whatever you found when parsing the string. */
i = va_arg(list_pointer, int);
/* Continue to do whatever you have to do */
}
va_start is something like :
Code: Select all
#define va_start(l, a) (l = (va_list)&a)
and va_arg is something like :
Code: Select all
#define va_arg(l, a) (l += (sizeof(a) + 3)&(~3); *(a*)l)
I don't remember if its a , or a ; that must be used in va_arg, but one of the two means 'return the last value of the list'.
BTW, va_list has to be equivalent to void* (via a typedef, for example).