views:

186

answers:

3

Let's say I want to do something like this

void my_printf(char *fmt,...) {
 char buf[big enough];
 sprintf(buf,fmt,...);  
}

What is the proper way of passing the variable number of arguments directly to a function with accepts variable arguments?

+9  A: 

sprintf has a va_list form called vsprintf. Pass the va_list you construct locally to it as the last argument.

void my_printf(char *fmt,...) {
 va_list ap;
 va_start(ap, fmt);

 char buf[big enough];
 vsprintf(buf,fmt,ap);

 va_end(ap);
}
Johannes Schaub - litb
The operative header is `<stdarg.h>`.
Mike DeSimone
If it's available, you should use `vsnprintf`.
R Samuel Klatchko
+1  A: 

I'm not sure how useful this code will be, as it is C++, but it shows how to check, using a Win32 specific function vsnprintf(), that the buffer allocated is big enough and if not allocates a bigger one. And it returns a std::string, so you would have to use malloc/realloc to handle that. But what the hell:

string Format( const char * fmt, ... ) {
    const int BUFSIZE = 1024;
    int size = BUFSIZE, rv = -1;
    vector <char> buf( size );
    do {
        va_list valist;
        va_start(valist, fmt );
        // if vsnprintf() returns < 0, the buffer wasn't big enough
        // so increase buffer size and try again
        rv = _vsnprintf( &buf[0], size, fmt, valist );
        va_end( valist );
        size *= 2;
        buf.resize( size );
    }
    while( rv < 0 );
    return string( &buf[0] );
}
anon
A: 

You can us the vsprintf style functions to get printf style printing for your variable length parameter. However there is no requrement to do so. You can if you choose write your function to keep accepting parameters until it encounters a null pointer.

 va_list ap;
char *param;
va_start(ap,fmt);
param = va_arg(ap,char*);
while(param)
{
do something...
param = va_arg(ap,char*);
}

or you can have the number of parameters as the first param to your function

void my_printf(int param_num,...)
{
 va_list ap;
char *param;
va_start(ap,fmt);
while(param_num)
{
do something...
param = va_arg(ap,char*);
param_num--;
}

}

Its really up to you, the possibilities are limitless. I think the only real requirement to the ellipses is that it has at least one parameter before the ellipses.

Medran
requiring the user to specify the number of parameters would be a design catastrophe
Mike
my point is the ... is not pigeon holed into a certain usage. The user of the function can decide what is best for their situation. Passing in the number of parameters is no different than having the number embeded in a string... ie sprintf("%d %d",a,b) is just the same as yourprintf(2,a,b), sprintf is just as prone to user error.
Medran