C Language Variable arguments

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Insert
> Step 2: And Like the video. BONUS: You can also share it!


Variable arguments are used by functions in the printf family (printf, fprintf, etc) and others to allow a function to be called with a different number of arguments each time, hence the name varargs.

To implement functions using the variable arguments feature, use #include <stdarg.h>.

To call functions which take a variable number of arguments, ensure there is a full prototype with the trailing ellipsis in scope: void err_exit(const char *format, ...); for example.


  • void va_start(va_list ap, last); /* Start variadic argument processing; last is the last function parameter before the ellipsis (“...”) */
  • type va_arg(va_list ap, type); /* Get next variadic argument in list; be sure to pass the correct promoted type */
  • void va_end(va_list ap); /* End argument processing */
  • void va_copy(va_list dst, va_list src); /* C99 or later: copy argument list, i.e. current position in argument processing, into another list (e.g. to pass over arguments multiple times) */


va_list apargument pointer, current position in the list of variadic arguments
lastname of last non-variadic function argument, so the compiler finds the correct place to start processing variadic arguments; may not be declared as a register variable, a function, or an array type
typepromoted type of the variadic argument to read (e.g. int for a short int argument)
va_list srccurrent argument pointer to copy
va_list dstnew argument list to be filled in


The va_start, va_arg, va_end, and va_copy functions are actually macros.

Be sure to always call va_start first, and only once, and to call va_end last, and only once, and on every exit point of the function. Not doing so may work on your system but surely is not portable and thus invites bugs.

Take care to declare your function correctly, i.e. with a prototype, and mind the restrictions on the last non-variadic argument (not register, not a function or array type). It is not possible to declare a function that takes only variadic arguments, as at least one non-variadic argument is needed to be able to start argument processing.

When calling va_arg, you must request the promoted argument type, that is:

  • short is promoted to int (and unsigned short is also promoted to int unless sizeof(unsigned short) == sizeof(int), in which case it is promoted to unsigned int).
  • float is promoted to double.
  • signed char is promoted to int; unsigned char is also promoted to int unless sizeof(unsigned char) == sizeof(int), which is seldom the case.
  • char is usually promoted to int.
  • C99 types like uint8_t or int16_t are similarly promoted.

Historic (i.e. K&R) variadic argument processing is declared in <varargs.h> but should not be used as it’s obsolete. Standard variadic argument processing (the one described here and declared in <stdarg.h>) was introduced in C89; the va_copy macro was introduced in C99 but provided by many compilers prior to that.

Got any C Language Question?