Skip navigation

Understanding va_list

Writing your own function that uses a va_list is really easy!

But first, let’s identify what a va_list is.

Think about the printf() C function.

printf(“Hello there! I like the numbers %d, %d and %d\n\n\n”, 1, 3, 7);

Obviously the output of that function call would be:

Hello there! I like the numbers 1, 3 and 7

But the key point here is, the printf() function can accept a VARYING NUMBER OF ARGUMENTS. That’s because it uses a va_list.

If you look at the signature for printf(), it looks like this:

int printf( char * format, … );

So the argument list for printf() has 2 main things:

  1. char * format – a regular string
  2. and a second special argument, … (3 dots, just like that)
  3. … is called an “ellipsis”, and it means, in plain English: “any number of optional arguments can go here.”

    So somehow, in the innermost bowels of printf(), is some sticky code that somehow retrieves each one of the the list of args you’re passing in, in the place of the “…”.

    Cool! So is it possible for us to write our functions that have their own sticky code that can process a set of VARIABLE ARGUMENTS???

    YES YOU CAN. And its actually simple!

    An example:

    #include <stdio.h>
    #include <stdarg.h>
    int addThemAll( int numargs, ... )
        // So this function can accept a variable number
        // of arguments.  No (practically speaking) limits.
        // RULES you must know in order to be able to use "..." in one of your
        // own functions:
        // 1)  The ... MUST appear exactly as ... 
        // It cannot be "..." (with the quotes),
        //     '...', or anything else weird.
        // 2)  The ... __MUST GO LAST__ IN THE ARGUMENT LIST
        //     THAT COMES BEFORE THE ...
        // We'll be using these macros here:
         va_list    va_start    va_end    va_arg
        // All of the above va_* things are actually special MACROS,
        // exclusively defined for us to use when working with
        // _V_ariable _A_rgument lists.
        // FIRST, we create a POINTER that will be used
        // to point to the first element of the VARIABLE
        // ARGUMENT LIST.
        va_list listPointer;
        // Currently, listPointer is UNINITIALIZED, however,
        // SO, now we make listPointer point to
        // the first argument in the list
        va_start( listPointer, numargs );
        // Notice that numargs is the LAST MANDATORY ARGUMENT
        // that the addThemAll() function takes.
        // By "LAST MANDATORY ARGUMENT", I mean 'numargs'
        // is the last argument to the addThemAll() function
        // JUST BEFORE the "..."
        // NEXT, we're going to start to actually retrieve
        // the values from the va_list itself.
        // FROM THE va_list.  In this example, I'm assuming
        // they're all ints, but you could always pass a format
        // string that lets you know the types.
        int sum = 0;
        for( int i = 0 ; i < numargs; i++ )
            // GET an arg.  YOU MUST KNOW
            // IT FROM THE va_list.
            int arg = va_arg( listPointer, int );
            printf( "    The %dth arg is %d\n", i, arg );
            sum += arg;
        printf("END OF ARGUMENT LIST\n\n");
        // FINALLY, we clean up by saying
        // va_end().  Don't forget to do this
        // BEFORE the addThemAll() function returns!
        va_end( listPointer );
        printf("The total sum was %d\n\n", sum);
        return sum;
    int main()
        // Try it out.
        printf("Calling 'addThemAll( 3, 104, 29, 46 );' . . .\n");
        addThemAll( 3, 104, 29, 46 );
        printf("Calling 'addThemAll( 8,   1, 2, 3, 4, 5, 6, 7, 8 );' . . .\n");
        addThemAll( 8,   1, 2, 3, 4, 5, 6, 7, 8 );
        return 0;

    Download Visual Studio project files.

    (donation should be to



    • Ran
    • Posted May 14, 2008 at 12:07 pm
    • Permalink

    OK. This is clear and simple. but what if I want to postpone processing the variable list for later? For example, say that I have a class A:
    class A{
    void setParams( int args, …);
    void processParams();
    surly I need to keep the variable parameters in A somehow between the call to ‘set’ and ‘process’. If you are looking for justification for such requirement, it is very simple: from one context you set the parameters and from another you process them.

  1. put them into an array!

    • Ran
    • Posted June 1, 2008 at 3:58 pm
    • Permalink

    Please be more specific. what is the type of this array? How to declare:
    myArray[ args ]; ?
    What is ?
    If I need to process the arguments to keep them, then it doesn’t help. I want to postpone the processing. I need something that looks like the stack when entering a function with ‘…’ parameters.
    Any suggestions?

  2. assuming, they’re all ints, you can maintain an array like:

    int * arr = (int*)malloc( numargs*sizeof(int) );

    for( int i = 0 ; i < numargs; i++ )
    // . . get arg, store in array

    careful of leaks!

    hope that helps

    • Ran
    • Posted June 4, 2008 at 8:44 am
    • Permalink

    Nope. If I know the types I have no problems. If it is only one type, even if I don’t know what is this type – still no problem (I can figure the type later and copy the parameters to the largest type acceptable array). I need the whole – different types, different number of variables, completely unseen. As it in printf. Actually, I need that my users will use my function exactly as they use printf. Only that the processing of %d, %p and alike will be done later, in a different task. I didn’t find a solution for this up till now.

    • Ran
    • Posted June 4, 2008 at 9:48 am
    • Permalink

    OK. After writing you the answer the solution entered my mind. The idea is to keep every variable in the list in the *maximum* storage that might be needed. That means, for instance, that every parameter is copied into a 4 bytes length field. then, if I have this code: Ranf( “char %c, int %d” ); they will both be copied into an array of 4 bytes fields:
    UINT32 myVariableTypes[ MAX_PARAMETERS ];
    Ranf( const char* text, … )
    //copy every parameter into //myVariableTypes. Later the string //’text’ will indicate the specific type

    The only problem is how to know the number of parameters. For this I can either scan ‘text’ or ask the user to supply it: Ranf( UINT8 noOfParameters, const char* text, … );
    It is a bit annoying but saves run time, which is very critical for me.

    what do you say?

  3. This is how I might do it.

    I’ve preserved the original datatypes as well.

    • Als
    • Posted October 3, 2008 at 2:24 am
    • Permalink

    your exemple is very clear and helpful.
    But i’d like to know how can i change value of vars as scanf do?

    • Kidar
    • Posted October 31, 2008 at 4:15 pm
    • Permalink

    Thank you for your example, it helped me to do my custom fprintf(UARTPutChar,”Hello World! %d”, year) function for example, that prints to UART output instead to stdin or string array.

  4. Here is a ANSI C example of how pass … from one function to another without intermediate pointer. I believe that works in C++ too


    my_funcv (const char *text, va_list args)
    printf(“I’m my_newv and I receive … from my_func\n”);
    printf(“Value is: %s\n”, text);
    char *value;
    while (value = va_arg(args, char *))
    printf(“Value is: %s\n”, value);

    my_func (const char *text, …)
    va_list args;
    va_start(args, text);
    my_funcv (text, args);
    va_end (args);

    main (int argc, char *argv[])
    my_func(“This”, “is”, “a”, “test”, NULL);
    return 0;

    • rocketGuy
    • Posted July 9, 2009 at 3:33 pm
    • Permalink

    Can you have a function that takes a variable argument list and directly pass it to another fucntion?

    void myLogger(char *format, int numArgs, …)
    systemLogger(char *format, int numArgs, …);
    or do you have to extract the argument then pass them on to the second function?

    void myLogger(cahr *format, int

  5. You can pass listPointer to another function, yes

    vsprintf is an example of a such function that accepts an already started va_list as an argument

    void log( char * fmt, ... ) 
      // create and start the va_list
      va_list listPointer ;
      va_start( listPointer, fmt ) ;
      // vsprintf is an example of
      // a function that works with
      // an "already started" va_list
      static char buf[ 1024 ] ;
      vsprintf( buf, fmt, listPointer ) ;
    • beezee
    • Posted August 28, 2009 at 4:38 pm
    • Permalink

    Very good discussion. Another way to pass va_list is by using va_copy. This creates a memory copy of the listPointer on the heap. This macro needs to be within the va_start and va_end block so that the memory assigned can be released.

    • peter
    • Posted September 7, 2009 at 12:55 pm
    • Permalink

    I am glsd to see the discussions here,
    But i ahve a doubt here. How to find out the second argument directly , i know the type previously.

    The condition is
    a) some times i have only one argument a char * string

    b) some time i have 2 arguments one a string and other an integer.

    How i will find out the existance of second argument.

    It will be very greatful i will get a proper reply. Thanks in advance.

    • The Big Priest
    • Posted September 30, 2009 at 8:49 am
    • Permalink

    Here’s another challange,
    What if I need to pass a different number of arguments to a function (one of a set).
    Consider the following code:

    void A::foo();
    void A::foo(int n1);
    void A::foo(int n1, int n2);
    void A::foo(int n1, int n2, int n3);

    void A::my_func(int num_args, …)
    // now I need to call specific foo()

    Do I have to parse the aguments before and then call the function? I mean with a set of ‘if’ statements [if (num_args==0) call this, if (num_args==1) call that and so on]
    Do I have a simple way?


  6. It looks like the way you’re doing it is the simplest way.

    void A::my_func(int num_args, ... )
      switch( num_args )
        case 0:
          foo() ;
        case 1:
          // pull 1 arg here,
          foo( arg ) ;

    I think you’re thinking of scripting languages like javascript where you can “form” the string of code you want to execute, then eval() it later. But in C++ at some point in the code you’re going to have to explicitly write the code that calls the 1 argument version, 2 argument version, etc

  7. I have a similar problem. I’m trying to wrap a C function with va_list into OCaml. Forget about OCaml, here. But the thing is I want to feed a list of unknown length to the function.

    I see only one solution to make a clean call this way: Bypass C, and use the C ABI of your platform directly. Calling conventions for multiple arguments is documented in the ABI, so you could wrap it there.

    The only reason I’m not doing that is that is becomes platform-specific. So my question is there any platform-agnostic, from C for example, to make a call via the ABI without knowing beforehand the number of argument?

    Or is va_list the only implementation of this feature in the ABI?

  8. Basically, my question is: how do constructed the data structure referenced by listPointer?

    • amit
    • Posted June 29, 2010 at 8:10 pm
    • Permalink

    I want to implement printf() using va_list,but no printf,cin can be used within the function.

    • Hemant kumar
    • Posted July 30, 2010 at 10:19 am
    • Permalink

    thankyou sir,
    your explanation are really more clear than the study material available on other website,,

    • bobobo
    • Posted July 30, 2010 at 10:33 am
    • Permalink

    I am da best

    • Andre
    • Posted September 8, 2010 at 10:28 pm
    • Permalink


    • Vinay kumar
    • Posted April 11, 2011 at 4:39 am
    • Permalink


    One doubt regarding the va_start()
    Here you have given the number of arguments as the first parameter to the function and hence used it in va_start().

    Is it mandatory to have the number of arguments always ?


    • Aman Gupta
    • Posted April 18, 2011 at 9:44 pm
    • Permalink

    Thank you buddy,
    You have explained it very very well …Thank you very much :)

    • Albert
    • Posted May 11, 2011 at 3:14 am
    • Permalink

    Thanks very much for your work!

    • Anonymous
    • Posted July 14, 2011 at 10:57 pm
    • Permalink

    Dude, this explanation was perfect, thanks so much!

    • Anonymous
    • Posted July 29, 2011 at 1:50 pm
    • Permalink

    yes bobbo you are the best:)

    • Anonymous
    • Posted October 12, 2011 at 2:34 pm
    • Permalink

    Very helpful text.

    • Mafahir
    • Posted October 14, 2011 at 11:35 am
    • Permalink

    This is the detailed code of how it really works

    void func(size_t size, …)

    *this statement is same as ‘var_list arg_list’
    char* arg_list;

    *get the memory address of the first parameter
    char* pSize = (char*)&size;

    *add the size of integer to the current pointer (each parameter is separated by bytes size of integer)
    *this statement is same as ‘var_start(arg_list,size)’
    arg_list = pSize + sizeof(int);

    for (size_t i = 0; i < size; i++)
    *To get the argument at index 'i' multiply that by the size of integer and add it to the list address
    *this statement is same as 'var_arg(arg_list)' but our statement is random iteratable
    char *t = (arg_list + (sizeof(int) * i));
    //do something here…

    /*this statement is same as 'var_end(arg_list)'
    arg_list = NULL;

    int main()
    func(7, //size of array
    'a','b','c','d','e','f','g'); //infinite arguments


  9. Quite amazed by the post .. elegantly written, but i am facing a problem in passing the format to the another function from a function like
    void fun2(char* format, ..)
    va_list args;
    va_start(args, format);
    vprintf(format, args);


    void fun1(char* format,…)



    int main()

    char* ptr = “Hi”;
    int intVar = 10;

    fun1(“I am saying %s for %d times”,ptr,intVar);

    return 0;


    This code doesnt work! Plz help me.. But if i try to print in fun1 function, it is working fine..

  10. sorry my previous post was supposed to be
    void fun2(char* format, …)
    va_list args;
    va_start(args, format);
    vprintf(format, args);


  11. Thanks A LOT! I always wondered how lists of arguments worked :) It was very clear and easy to follow.

    • theJackal
    • Posted January 11, 2013 at 7:51 am
    • Permalink

    I have a question regarding returning in the variadic (variable argumnets) functions.
    Suppose I want to return value in the parameters I am passing to the variadic function, how can I do that?

    The sample code I want to use it in looks something like this,

    int main(void) {
    int val1;
    int val2;
    custom_funct(2, &val1, &val2);
    printf(“val1 = %d, val2 = %d”, val1, val2);
    return 0;

    void custom_funct(int num_args, …) {
    va_list arglist;
    va_start(arglist, num_args);

    // assign values using pointers to val1 and val2.
    // for example,
    // val1 = 100; val2 = 200;

  12. Aw, this was an extremely nice post. Spending some time and actual effort to
    produce a really good article… but what can I say… I
    hesitate a lot and don’t manage to get anything done.

    • Joaquim Miguel
    • Posted August 19, 2013 at 11:22 am
    • Permalink

    big question: how can i know how many arguments was added to the function?
    (instead use the “int num_args”)
    what i mean is these:
    1 – the user put how many parameters he need for do the job;
    2 – how the function can calculate how many parameters was added to the function?

4 Trackbacks/Pingbacks

  1. […] } I metodi che si aspettano un numero variabile di parametri li gestiscono utilizzando la sintassi del linguaggio C, che prevede l’uso di va_list e va_start. Per esempio: – (void)setValori:valori, … { va_list ap; va_sart(ap, group); // …. } Un approfondimento si trova qui. […]

  2. By getting the max of some numbers on 03 Dec 2010 at 5:30 pm

    […] […]

  3. […] to understand the underlying structure of variable arguments and in particular va_list. This blog does a really good […]

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: