70
void TestPrint(char* format, ...)
{
    va_list argList;

    va_start(argList, format);
    printf(format, argList);
    va_end(argList);
}


int main()
{
    TestPrint("Test print %s %d\n", "string", 55);
    return 0;
}

I need to get:

Test print string 55

Actually, I get garbage output. What is wrong in this code?

Alex F
  • 42,307
  • 41
  • 144
  • 212

5 Answers5

88

Use vprintf() instead.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
71

Instead of printf, I recommend you try vprintf instead, which was created for this specific purpose:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

void errmsg( const char* format, ... )
{
    va_list arglist;

    printf( "Error: " );
    va_start( arglist, format );
    vprintf( format, arglist );
    va_end( arglist );
}

int main( void )
{
    errmsg( "%s %d %s", "Failed", 100, "times" );
    return EXIT_SUCCESS;
}

Source

Neuron
  • 5,141
  • 5
  • 38
  • 59
onteria_
  • 68,181
  • 7
  • 71
  • 64
25

As others have pointed out already: In this case you should use vprintf instead.

But if you really want to wrap printf, or want to wrap a function that does not have a v... version, you can do that in GCC using the non-standard __builtin_apply feature:

int myfunction(char *fmt, ...)
{
    void *arg = __builtin_apply_args();
    void *ret = __builtin_apply((void*)printf, arg, 100);
    __builtin_return(ret);
}

The last argument to __builtin_apply is the max. total size of the arguments in bytes. Make sure that you use a value here that is large enough.

CliffordVienna
  • 7,995
  • 1
  • 37
  • 57
  • 2
    thanks for that answer, which gives a straight solution to OP's problem. For interception purpose, this code saved my life! (or at least avoided me to defer to assembly :) – Kevin Oct 27 '15 at 09:58
  • 2
    Can there EVER be a maximum for this value? The `__builtin_apply()` should parse the call stack frames in order to find out the value on its own. But it depends on the architecture if and how good this would work. I once grafted a similar solution for myself. It was horrible. – glglgl May 14 '18 at 08:03
4

This is not how you use printf(). If you want to use va_lists, use vprintf() instead. Look here for reference.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Constantinius
  • 34,183
  • 8
  • 77
  • 85
0

For anybody who needs more universal solution - try this template function:

template<typename... Args>
void myprintf(const char *format, Args... args)
{
    myObject.printf(format, args...);
}
Clive Dent
  • 21
  • 4