Passing parameters dynamically to variadic functions
I was wondering if there was any way to pass parameters dynamically to variadic functions. i.e. If I have a function
int some_function (int a, int b, ...){/*blah*/}
and I am accepting a bunch of values from the user, I want some way of passing those values into the function:
some_function (a,b, val1,val2,...,valn)
I don't want to write different versions of all these functions, but I suspect there is no other option?
Solution 1:
Variadic functions use a calling convention where the caller is responsible for popping the function parameters from the stack, so yes, it is possible to do this dynamically. It's not standardized in C, and normally would require some assembly to manually push the desired parameters, and invoke the variadic function correctly.
The cdecl
calling convention requires that the arguments be pushed in the correct order, and after the call, the bytes pushed as arguments before the call are popped. In this way, the called function can receive an arbitrary number of parameters, as the caller will handle reverting the stack pointer to it's pre-call state. The space occupied by the arguments before the ...
is the safe lower bound for number of bytes pushed. Additional variadic arguments are interpreted at runtime.
FFCALL is a library which provides wrappers for passing parameters dynamically to variadic functions. The group of functions you're interested in is avcall. Here's an example calling the functions you gave above:
#include <avcall.h>
av_alist argList;
int retVal;
av_start_int(argList, some_function, retval);
av_int(argList, a);
av_int(argList, b);
av_type(argList, val1);
...
av_type(argList, valn);
av_call(argList);
You might also find this link discussing generating wrappers around variadic functions in C, to be of interest in justifying why this isn't part of standard C.
Solution 2:
A standard approach is to have each variadic function accompanied by a va_list
-taking counterpart (as in printf and vprintf). The variadic version just converts ...
to a va_list
(using macros from stdarg.h
) and calls its va_list-taking sister, which does actual work.