liveBook · Manning

Variadic arguments

As explained in Modern C

A variadic function is a C function that accepts a variable number of arguments through an ellipsis in its parameter list.

A variadic function accepts a variable number of arguments by placing an ellipsis (...) after its known parameters. Calls provide the initial arguments, such as printf’s format, followed by any number of additional values. section 16.5

The interface is difficult because the compiler cannot determine the expected type of each variadic argument. Arithmetic arguments undergo the usual promotions, except float becomes double; char and short commonly become int. The called function still needs valid type information for every value. section 16.5.2

Reading a counted list

double sumIt(size_t n, ...) { double ret = 0.0; va_list va; va_start(va, n); for (size_t i = 0; i < n; ++i) ret += va_arg(va, double); va_end(va); return ret; } Here, n states how many additional arguments follow. va_start initializes traversal, va_arg reads each value as double, and va_end finishes it. The caller must pass values compatible with those expectations.

Format-directed interpretation

printf("%hhu", zChar); zChar is promoted to int before the call; printf uses %hhu to interpret the received value as unsigned char. Format specifications therefore carry type information outside the function’s parameter list. section 16.5.2

20   FILE* iodebug = 0;
21
22   /**
23    ** @brief Prints to the debug stream @c iodebug 
24    **/ 
25   #ifdef __GNUC__
26   __attribute__((format(printf, 1, 2)))
27   #endif
28   int printf_debug(const char *format, ...) {
29     int ret = 0;
30     if (iodebug) {
31       va_list va;
32       va_start(va, format);
33       ret = vfprintf(iodebug, format, va);
34       va_end(va);
35     }
36     return ret;
37   }


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":2}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":9}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":2}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":2}],[{\"line\":3,\"ch\":0},{\"line\":3,\"ch\":2}],[{\"line\":4,\"ch\":0},{\"line\":4,\"ch\":2}],[{\"line\":5,\"ch\":0},{\"line\":5,\"ch\":2}],[{\"line\":5,\"ch\":5},{\"line\":5,\"ch\":11}],[{\"line\":6,\"ch\":0},{\"line\":6,\"ch\":2}],[{\"line\":6,\"ch\":27},{\"line\":6,\"ch\":33}],[{\"line\":8,\"ch\":9},{\"line\":8,\"ch\":15}],[{\"line\":13,\"ch\":17},{\"line\":13,\"ch\":23}],[{\"line\":7,\"ch\":0},{\"line\":7,\"ch\":2}],[{\"line\":7,\"ch\":5},{\"line\":7,\"ch\":11}],[{\"line\":8,\"ch\":0},{\"line\":8,\"ch\":2}],[{\"line\":3,\"ch\":18},{\"line\":3,\"ch\":21}],[{\"line\":6,\"ch\":29},{\"line\":6,\"ch\":32}],[{\"line\":8,\"ch\":5},{\"line\":8,\"ch\":8}],[{\"line\":9,\"ch\":7},{\"line\":9,\"ch\":10}],[{\"line\":13,\"ch\":19},{\"line\":13,\"ch\":22}],[{\"line\":8,\"ch\":22},{\"line\":8,\"ch\":32}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":2}],[{\"line\":3,\"ch\":18},{\"line\":3,\"ch\":21}],[{\"line\":6,\"ch\":29},{\"line\":6,\"ch\":32}],[{\"line\":8,\"ch\":5},{\"line\":8,\"ch\":8}],[{\"line\":9,\"ch\":7},{\"line\":9,\"ch\":10}],[{\"line\":13,\"ch\":19},{\"line\":13,\"ch\":22}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":2}],[{\"line\":5,\"ch\":6},{\"line\":5,\"ch\":8}],[{\"line\":7,\"ch\":9},{\"line\":7,\"ch\":11}],[{\"line\":10,\"ch\":7},{\"line\":10,\"ch\":9}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":2}],[{\"line\":11,\"ch\":9},{\"line\":11,\"ch\":16}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":2}],[{\"line\":12,\"ch\":9},{\"line\":12,\"ch\":17}],[{\"line\":13,\"ch\":0},{\"line\":13,\"ch\":2}],[{\"line\":13,\"ch\":15},{\"line\":13,\"ch\":23}],[{\"line\":14,\"ch\":0},{\"line\":14,\"ch\":2}],[{\"line\":14,\"ch\":9},{\"line\":14,\"ch\":15}],[{\"line\":15,\"ch\":0},{\"line\":15,\"ch\":2}],[{\"line\":16,\"ch\":0},{\"line\":16,\"ch\":2}],[{\"line\":16,\"ch\":7},{\"line\":16,\"ch\":13}],[{\"line\":17,\"ch\":0},{\"line\":17,\"ch\":2}]]"}
!@%STYLE%@!

Shows a debug-printing wrapper that forwards its variadic arguments to vfprintf and brackets traversal with va_start and va_end. section 16.5.2

How Modern C covers it

How deep it goes
Explains ellipsis syntax, default promotions, type contracts, and va_list traversal, but defers detailed implementation and discourages new use.
Examples
Uses printf format specifications, a counted double-summing function, and a debug-stream wrapper forwarding to vfprintf.
What it assumes
Assumes function declarations and calls, while teaching ellipsis syntax, argument promotions, and explicit type communication.
What you can do after
Operate stdarg interfaces with va_start, va_arg, and va_end, and diagnose mismatched format specifications or argument types.
How it connects
Connects variadic arguments to function prototypes, default argument promotions, format strings, stdarg interfaces, and variadic macros.

Also explained in

Compare how 8 books explain variadic arguments →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.