Reputation: 1
#define exampleA(buf, args...) \
exampleB(buf, ##args); \
}
#endif
works where the exampleB function declaration is exampleB(char* buf, ...). But I need to change the declaration as exampleB(char* buf, va_list args). How can change the marco accordingly?
Upvotes: 0
Views: 500
Reputation: 241671
You cannot. In order to create a va_list
, you need to have a variadic function. There is no portable facility to create a va_list
object from a list of arguments.
It is quite common to write variadic functions in pairs: the outer function uses the facilities in <stdarg.h>
to construct a va_list
, and it passes that list directly to the function which does the work. You see that in the standarid I/O library, for example: printf
/vprintf
, fprintf
/vfprintf
, snprintf
/vsnprintf
, scanf
/vscanf
, etc.
And that's what you should do for your problem: write exampleB
as the va_list
form of exampleA
.
Here, for example, is the entire implementation of the fprintf
function extrated from the FreeBSD library, which can serve as a model of this style:
int
fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf_l(fp, __get_locale(), fmt, ap);
va_end(ap);
return (ret);
}
As you can see from that snippet, vfprintf_l
(which takes a locale argument) is actually the implementation; all the other *printf
functions are simple wrappers. (printf
, for examples, calls vfprintf_l
passing stdin
and the locale argument.) That avoids having to traverse multiple wrappers in a single call, although modern optimising compilers are usually able to do that elimination automatically.
(See lib/libc/stdio/fprintf.c for the full file in the FreeBSD source repository mirror on Github.)
Speaking of portability, #define exampleA(buf, args...)
is a GCC extension which is not portable to most C implementations (although Clang implements it as well). You should use __VA_ARGS__
as per standard C:
#define exampleA(buf, ...) \
exampleB(buf, ## __VA_ARGS__)
Even better, if you can, replace the other GCC extension (, ##
) with the newer standard __VA_OPT__
:
#define exampleA(buf, ...) \
exampleB(buf __VA_OPT__(,) __VA_ARGS__)
Upvotes: 5
Reputation: 109
I don't think this is possible the way you imagine it.
Let's consider a function exampleX(char *,...)
: the arguments you pass must live somewhere and let's say they are pushed to the stack. The va_list
macros know that and can access them from there. The moment you leave that function, the arguments cannot be assumed to be on the stack anymore.
Thus, you may not write a helper function like va_list getArgs(char*x,...) { /* use va_start and return the va_list */ }
and pass that va_list
to exampleB
.
The only thing I can think of is to write a trampoline function such as
void callExampleB(char * buf, ...) {
va_list ap;
va_start(ap, buf);
exampleB(buf, ap);
va_end(ap);
}
and call that in your macro.
Upvotes: 2