Skip to content
Search

Cstdarg

lastmod 2023-04-04created 2019-03-047 edits

Variadic arguments in C.

Implementation

va_list
A pointer that will point to the start address of each variadic argument. It looks fancy, but internally it is defined as char *.
va_start
An important macro that tells the pointer created with va_list the address of the first of the variadic arguments. It actually looks like this. (Based on Microsoft Visual Studio)

:

#define va_start(ap, v)  ( (ap) = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

:* ap: Holds the pointer created with va_list.

:* v: Holds the last fixed argument.

:* _ADDRESSOF(v) => &(v), a macro that converts it into an address.

:* _INTSIZEOF(n) => ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ), a macro that gets the size of the last fixed argument and computes the in-memory distance to the start address of the next argument, i.e. the start address of the variadic arguments.

va_arg
A macro that moves the va_list pointer, which points to a particular variadic argument, to the next variadic argument. It looks like this.

:

#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

:* ap: Holds the pointer created with va_list.

:* t: Holds a type name such as int, long, or double.

Note that for char and short you reportedly have to use int instead, and for flaot use double instead, and then cast the type. (e.g. char ch = (char) va_arg(ap, int); )
va_end
Used when you are done with the variadic argument variable. Looking at its form, it's simply a macro that sets the pointer back to NULL, but since you never know what might happen in a program, make sure not to skip it.

:

#define va_end(ap)      ( ap = (va_list)0 )

:* ap: Holds the pointer created with va_list.

Example

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

int sum(int, ...);

int main(void) {
   printf("Sum of 10, 20 and 30 = %d\n",  sum(3, 10, 20, 30) );
   printf("Sum of 4, 20, 25 and 30 = %d\n",  sum(4, 4, 20, 25, 30) );

   return 0;
}

int sum(int num_args, ...) {
   int val = 0;
   va_list ap;
   int i;

   va_start(ap, num_args);
   for(i = 0; i < num_args; i++) {
      val += va_arg(ap, int);
   }
   va_end(ap);

   return val;
}

Printf example

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

void
foo(char *fmt, ...)
{
    va_list ap;
    int d;
    char c, *s;

    va_start(ap, fmt);
    while (*fmt)
        switch (*fmt++) {
        case 's':              /* string */
            s = va_arg(ap, char *);
            printf("string %s\n", s);
            break;
        case 'd':              /* int */
            d = va_arg(ap, int);
            printf("int %d\n", d);
            break;
        case 'c':              /* char */
            /* need a cast here since va_arg only
               takes fully promoted types */
            c = (char) va_arg(ap, int);
            printf("char %c\n", c);
            break;
        }
    va_end(ap);
}

How to pass a va_list

void _printf(const char * format, ...)
{
    char buffer[2048] = {0,};
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, 2048, format, args);
    va_end(args);

    _print(buffer);
}

See also

Favorite site

References


  1. Norux.me_-_How_to_use_the_va_list.pdf ↩

author Zer0 sitemap