Table of Contents

stdarg.h

stdarg.h provides the machinery for writing variadic functions — functions that accept a variable number of arguments, like printf. Without it you would have no portable way to iterate over the unnamed arguments. It defines va_list, and the va_start, va_arg, va_end, and va_copy macros.

#include <stdarg.h>
#include <stdio.h>
 
int sum(int count, ...) {
    va_list ap;
    va_start(ap, count);        // initialise: 'count' is the last named param
 
    int total = 0;
    for (int i = 0; i < count; i++)
        total += va_arg(ap, int);   // pull the next argument as int
 
    va_end(ap);                 // mandatory cleanup
    return total;
}
 
// sum(4, 10, 20, 30, 40) → 100

va_start(ap, last) initialises the list starting just after last (the final named parameter). va_arg(ap, type) reads the next argument and advances the cursor. va_end(ap) must be called before the function returns.

va_copy(dst, src) copies a va_list so you can traverse the arguments twice — useful when you call vsnprintf once to measure the required buffer length and again to fill it.

There is no type safety: va_arg trusts the type you give it. If the caller passed a double but you read it as int, you get undefined behaviour and likely garbage. printf encodes expected types in the format string; other variadic APIs use a sentinel value or an explicit count argument as the contract.

Practice

// compile: gcc -o vademo vademo.c
// run: ./vademo
// description: variadic minimum function using va_list
 
#include <stdarg.h>
#include <stdio.h>
#include <limits.h>
 
int vmin(int count, ...) {
    va_list ap;
    va_start(ap, count);
    int m = INT_MAX;
    for (int i = 0; i < count; i++) {
        int v = va_arg(ap, int);
        if (v < m) m = v;
    }
    va_end(ap);
    return m;
}
 
int main(void) {
    printf("min(3, 7, 1, 9)    = %d\n", vmin(4, 3, 7, 1, 9));
    printf("min(42)            = %d\n", vmin(1, 42));
    printf("min(empty)         = %d\n", vmin(0));   // INT_MAX — no args
    return 0;
}

Try passing a double where an int is expected by adding vmin(1, 3.14). On most platforms you will get a garbage result rather than a crash — that is the risk of variadic functions without runtime type checking. The count-based approach here is one way to bound the iteration; the other common approach is a NULL sentinel at the end of the argument list.