Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Process va_args in c++

I have a function A(...) and B(...). Now I have to call B inside A, any methods to pass that ... from A into B? Pseudocode:

void A(...)
{
   // Some operators
   B(...); // Instead of ... I need to pass A's args
}

p.s. I know this could be done using macros but what about functions.

like image 764
Max Frai Avatar asked Feb 17 '12 13:02

Max Frai


People also ask

What is Va_args?

va_arg returns the value of the next argument in a varying-length argument list. The first argument, ap , is a work area of type va_list , which is used by the expansions of the various <stdarg. h> macros.

Where is __ Va_args __ defined?

The C standard mandates that the only place the identifier __VA_ARGS__ can appear is in the replacement list of a variadic macro. It may not be used as a macro name, macro argument name, or within a different type of macro. It may also be forbidden in open text; the standard is ambiguous.

How does va_list work in C?

In the most usual stack-based situation, the va_list is merely a pointer to the arguments sitting on the stack, and va_arg increments the pointer, casts it and dereferences it to a value. Then va_start initialises that pointer by some simple arithmetic (and inside knowledge) and va_end does nothing.

What is variable arguments in C?

Variable length argument is a feature that allows a function to receive any number of arguments. There are situations where we want a function to handle variable number of arguments according to requirement. 1) Sum of given numbers.


3 Answers

You can't forward va_args. You can only forward va_list.

void vB(int first, va_list ap)
{
   // do stuff with ap.
}

void B(int first, ...)
{
   va_list ap;
   va_start(ap, first);
   vB(first, ap);
   va_end(ap);
}

void A(int something_else, int first, ...)
{
   va_list ap;
   va_start(ap, first);
   vB(first, ap);       // <-- call vB instead of B.
   va_end(ap);
}

(This is also why functions like vprintf exists.)


If you are using C++11, you could do this with variadic templates with perfect forwarding:

template <typename... T>
void A(T&&... args)
{
    B(std::forward<T>(args)...);
}
like image 128
kennytm Avatar answered Nov 10 '22 09:11

kennytm


Unfortunately you can't take a va-list and pass it to a function accepting a variable argument list. There is no syntax allowing you to expand the va_args structure back into parameters.

You can pass it as a va_list in a single parameter, so one solution would be to define the function that does the work as taking a va_list. Then you can define another function wrapping it taking an argument list which can then pass a va_list to the core function and pass the return value back. You see this kind of pattern in the C standard library with printf() and vprintf() and similar pairings.

like image 33
Matthew Walton Avatar answered Nov 10 '22 08:11

Matthew Walton


You need to slightly change the signature of your methods. I assume you want to do something like this:

void B(int numParams, va_list parameters)
{
    // Your code here. Example:
    for (int i=0; i<numParams; i++)
    {
        // Do something using va_arg to retrieve your parameters
    }
}

void A(int numParams, ...)
{
    va_list parameters;
    va_start(parameters, numParams);
    B(numParams, parameters);
    va_end(parameters);
}
like image 44
Riccardo Tramma Avatar answered Nov 10 '22 09:11

Riccardo Tramma