Passing variable arguments to another function that accepts a variable argument list


Passing variable arguments to another function that accepts a variable argument list



So I have 2 functions that both have similar arguments


void example(int a, int b, ...);
void exampleB(int b, ...);



Now example calls exampleB, but how can I pass along the variables in the variable argument list without modifying exampleB (as this is already used elsewhere too).


example


exampleB


exampleB





possible duplicate of Forward an invocation of a variadic function in C
– Greg Hewgill
Aug 20 '10 at 12:25





Well the solution on that one was using vprintf, and that's not the case here.
– Not Available
Aug 22 '10 at 7:57




7 Answers
7



You can't do it directly; you have to create a function that takes a va_list:


va_list


#include <stdarg.h>

static void exampleV(int b, va_list args);

void example(int a, int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
va_end(args);
}

void exampleB(int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
va_end(args);
}

static void exampleV(int b, va_list args)
{
...whatever you planned to have exampleB do...
...except it calls neither va_start nor va_end...
}





Suspected I had to do something like this, problem is the example function is basically a wrapper for vsprintf and not much else :/
– Not Available
Aug 20 '10 at 13:06





@Xeross: Note that this does not change the external specification of what exampleB does - it just changes the internal implementation. I'm not sure what the problem is.
– Jonathan Leffler
Aug 21 '10 at 4:54





I have handled it similarly to this, thanks.
– Not Available
Aug 22 '10 at 7:57



you should create versions of these functions which take a va_list, and pass those. Look at vprintf as an example:


vprintf


int vprintf ( const char * format, va_list arg );



Maybe throwin a rock in a pond here, but it seems to work pretty OK with C++11 variadic templates:


#include <stdio.h>

template<typename... Args> void test(const char * f, Args... args) {
printf(f, args...);
}

int main()
{
int a = 2;
test("%sn", "test");
test("%s %d %d %pn", "second test", 2, a, &a);
}



At the very least, it works with g++.


g++



Incidentally, many C implementations have an internal v?printf variation which IMHO should have been part of the C standard. The exact details vary, but a typical implementation will accept a struct containing a character-output function pointer and information saying what's supposed to happen. This allows printf, sprintf, and fprintf to all use the same 'core' mechanism. For example, vsprintf might be something like:



The core_printf function then calls p_inf->func for each character to be output; the output function can then send the characters to the console, a file, a string, or something else. If one's implementation exposes the core_printf function (and whatever setup mechanism it uses) one can extend it with all sorts of variations.



I also wanted to wrap printf and found a helpful answer here:



How to pass variable number of arguments to printf/sprintf



I was not at all interested in performance (I'm sure this piece of code can be improved in a number of ways, feel free to do so :) ), this is for general debugprinting only so I did this:


//Helper function
std::string osprintf(const char *fmt, ...)
{
va_list args;
char buf[1000];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args );
va_end(args);
return buf;
}



which I then can use like this


Point2d p;

cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y);
instead of for example:
cout << "Point2d: ( " << setw(3) << p.x << ", " << p.y << " )";



The c++ ostreams are beautiful in some aspects, but practically the become horrific if you want to print something like this with some small strings such as parenthesis, colons and commas inserted between the numbers.



Based on the comment that you're wrapping vsprintf, and that this is tagged as C++ I'd suggest not trying to do this, but change up your interface to use C++ iostreams instead. They have advantages over the print line of functions, such as type safety and being able to print items that printf wouldn't be able to handle. Some rework now could save a significant amount of pain in the future.


vsprintf


print


printf





To what advantages are you referring?
– cjcurrie
Jan 12 '13 at 6:27





@cjcurrie: the advantage is type safety, even with user-defined types. The C functions cannot handle user-defined types at all, of course.
– Jonathan Leffler
Apr 8 '13 at 7:29



Using the new C++0x standard, you may be able to get this done using variadic templates or even convert that old code to the new template syntax without breaking anything.





unfortunately this is not possible in all instances - just try using lambdas
– serup
Jan 31 '17 at 11:41






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

Possible Unhandled Promise Rejection (id: 0): ReferenceError: user is not defined ReferenceError: user is not defined

Opening a url is failing in Swift