C Language Variable arguments Using terminator values to determine the end of va_list


Example

With any variadic function, the function must know how to interpret the variable arguments list. The “traditional” approach (exemplified by printf) is to specify number of arguments up front. However, this is not always a good idea:

/* First argument specifies the number of parameters; the remainder are also int */
extern int sum(int n, ...);

/* But it's far from obvious from the code. */
sum(5, 2, 1, 4, 3, 6)

/* What happens if i.e. one argument is removed later on? */
sum(5, 2, 1, 3, 6)  /* Disaster */

Sometimes it's more robust to add an explicit terminator, exemplified by the POSIX execlp() function. Here's another function to calculate the sum of a series of double numbers:

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

/* Sums args up until the terminator NAN */
double sum (double x, ...) {
  double sum = 0;
  va_list va;

  va_start(va, x);
  for (; !isnan(x); x = va_arg(va, double)) {
    sum += x;
  }
  va_end(va);

  return sum;
}

int main (void) {
  printf("%g\n", sum(5., 2., 1., 4., 3., 6., NAN));
  printf("%g\n", sum(1, 0.5, 0.25, 0.125, 0.0625, 0.03125, NAN));
}

Good terminator values:

  • integer (supposed to be all positive or non-negative) — 0 or -1
  • floating point types — NAN
  • pointer types — NULL
  • enumerator types — some special value