Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing va_list to other functions

I have been trying to pass variable arguments to other function in C but it is producing inconsistent result in different runtime environment as well as in different runs in same environment:

int main() 
{ 
    int result = myprintf("Something \n %d", 9); 
    return result;
}

int myprintf(const char *format, ...){
    printf("Something \n %d", 9); 
    printf("\n");
    va_list args;        
    va_start(args, format);    
    int result = printf(format,args);
    printf("\n");
    va_end(args);
    return result;
} 

And the result produced is:

WWW.FIRMCODES.COM 
 9
WWW.FIRMCODES.COM 
 438656664

I could not find the reason for "438656664".

like image 624
Monk Avatar asked Apr 27 '16 06:04

Monk


People also ask

Can you pass va_list to another function?

The va_list may be passed as an argument to another function, but calling va_arg() within that function causes the va_list to have an indeterminate value in the calling function. As a result, attempting to read variable arguments without reinitializing the va_list can have unexpected behavior.

How do you pass a Vararg to a function?

In Kotlin, You can pass a variable number of arguments to a function by declaring the function with a vararg parameter. a vararg parameter of type T is internally represented as an array of type T ( Array<T> ) inside the function body.

Can we pass a variable argument list to a function at runtime?

Explanation: Every actual argument list must be known at compile time.

Is va_list a pointer?

The type va_list is used for argument pointer variables.


2 Answers

You cannot pass the variadic arguments to a variadic function. Instead, you must call a function that takes a va_list as argument. The standard library provides variants of printf and scanf that take a va_list; their names have the prefix v.

Your example should look like:

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

int printfln(const char *format, ...)
{
    int result;
    va_list args;

    va_start(args, format);
    result = vprintf(format, args);
    printf("\n");
    va_end(args);

    return result;
}

int main()
{
    int result = printfln("Something \n %d", 9);

    printf("(%d)\n", result);

    return 0;
}

There are some gotchas, for example when you want to call two v... function for printing to the screen and a log file: The v... function may exhaust the va_list, so you must pass in a fresh one to each call if your code should be portable.

like image 53
M Oehm Avatar answered Oct 19 '22 20:10

M Oehm


For the C++ fellow also reading this. You can actually do it using pack expansion without using vprintf. This trick is quite handy when you need to wrap a method that takes the ellipsis (...) and not a va_list.

For instance:

template <class ... Args>
void foo(const char *format, Args ... args)
{
    printf(format, args...);
}

Here class ... Args is template parameter pack, Args ... args is function parameter pack, and args... is function parameter pack expansion.

like image 42
Guillaume.P Avatar answered Oct 19 '22 22:10

Guillaume.P