In C, is it possible to forward the invocation of a variadic function? As in,
int my_printf(char *fmt, ...) {
fprintf(stderr, \"Calling printf with fmt %
If you don't have a function analogous to vfprintf
that takes a va_list
instead of a variable number of arguments, you can't do it. See http://c-faq.com/varargs/handoff.html.
Example:
void myfun(const char *fmt, va_list argp) {
vfprintf(stderr, fmt, argp);
}
C99 supports macros with variadic arguments; depending on your compiler, you might be able to declare a macro that does what you want:
#define my_printf(format, ...) \
do { \
fprintf(stderr, "Calling printf with fmt %s\n", format); \
some_other_variadac_function(format, ##__VA_ARGS__); \
} while(0)
In general, though, the best solution is to use the va_list form of the function you're trying to wrap, should one exist.
There's no way to forward such function calls because the only location where you can retrieve raw stack elements is in my_print()
. The usual way to wrap calls like that is to have two functions, one that just converts the arguments into the various varargs
structs, and another that actually operates upon those structs. Using such a double-function model, you can (for example) wrap printf()
by initializing the structs in my_printf()
with va_start()
, and then pass them to vfprintf()
.
Use vfprintf:
int my_printf(char *fmt, ...) {
va_list va;
int ret;
va_start(va, fmt);
ret = vfprintf(stderr, fmt, va);
va_end(va);
return ret;
}
Not directly, however it is common (and you will find almost universally the case in the standard library) for variadic functions to come in pairs with a varargs
style alternative function. e.g. printf
/vprintf
The v... functions take a va_list parameter, the implementation of which is often done with compiler specific 'macro magic', but you are guaranteed that calling the v... style function from a variadic function like this will work:
#include <stdarg.h>
int m_printf(char *fmt, ...)
{
int ret;
/* Declare a va_list type variable */
va_list myargs;
/* Initialise the va_list variable with the ... after fmt */
va_start(myargs, fmt);
/* Forward the '...' to vprintf */
ret = vprintf(fmt, myargs);
/* Clean up the va_list */
va_end(myargs);
return ret;
}
This should give you the effect that you are looking for.
If you are considering writing a variadic library function you should also consider making a va_list style companion available as part of the library. As you can see from your question, it can be prove useful for your users.
Not sure if this helps to answer OP's question since I do not know why the restriction for using a helper function akin to vfprintf in the wrapper function applies. I think the key problem here is that forwarding the variadic argument list without interpreting them is difficult. What is possible, is to perform the formatting (using a helper function akin to vfprintf: vsnprintf) and forward the formatted output to the wrapped function with variadic arguments (i.e. not modifying the definition of the wrapped function). So, here we go:
#include <stdio.h>
#include <stdarg.h>
int my_printf(char *fmt, ...)
{
if (fmt == NULL) {
/* Invalid format pointer */
return -1;
} else {
va_list args;
int len;
/* Initialize a variable argument list */
va_start(args, fmt);
/* Get length of format including arguments */
len = vsnprintf(NULL, 0, fmt, args);
/* End using variable argument list */
va_end(args);
if (len < 0) {
/* vsnprintf failed */
return -1;
} else {
/* Declare a character buffer for the formatted string */
char formatted[len + 1];
/* Initialize a variable argument list */
va_start(args, fmt);
/* Write the formatted output */
vsnprintf(formatted, sizeof(formatted), fmt, args);
/* End using variable argument list */
va_end(args);
/* Call the wrapped function using the formatted output and return */
fprintf(stderr, "Calling printf with fmt %s", fmt);
return printf("%s", formatted);
}
}
}
int main()
{
/* Expected output: Test
* Expected error: Calling printf with fmt Test
*/
my_printf("Test\n");
//printf("Test\n");
/* Expected output: Test
* Expected error: Calling printf with fmt %s
*/
my_printf("%s\n", "Test");
//printf("%s\n", "Test");
/* Expected output: %s
* Expected error: Calling printf with fmt %s
*/
my_printf("%s\n", "%s");
//printf("%s\n", "%s");
return 0;
}
I came across this solution here.
Editted: fixed mistakes pointed out by egmont