Simple patterns.
This is the typical template for a variadic function:
int add(int arg_count, ...) { int sum = 0; va_list args; va_start(args, arg_count); for (int i = 0; i < arg_count; i++) { sum += va_arg(args, int); } va_end(args); return sum; } int main(int argc, char** argv) { printf("1 + 2 + 3 = %d\n", add(3, 1, 2, 3)); return 0; }
printf
–style library function
All the standard library's printf
–style functions have a v
–prefaced variant that takes a va_list
argument.
void custom_printf(const char* format_string, ...) { va_list args; va_start(args, format_string); vprintf(format_string, args); va_end(args); } int main(int argc, char** argv) { custom_printf("%s and %s\n", "foo", "bar"); return 0; }
You can't chain variadic functions directly — i.e. one variadic function can't call another — but you can chain them indirectly by passing a va_list
argument.
int vadd(int arg_count, va_list args) { int sum = 0; for (int i = 0; i < arg_count; i++) { sum += va_arg(args, int); } return sum; } int add(int arg_count, ...) { va_list args; va_start(args, arg_count); int sum = vadd(arg_count, args); va_end(args); return sum; } int main(int argc, char** argv) { printf("1 + 2 + 3 = %d\n", add(3, 1, 2, 3)); return 0; }
This is a useful pattern — a v
–prefaced function that takes a va_list
argument and does the real work along with a variadic function that provides the default interface.
(This is the way the standard library's printf
–style functions are designed.)
printf
–style library function
You can pass a va_list
argument through multiple links of a chain.
void custom_vprintf(const char* format_string, va_list args) { vprintf(format_string, args); } void custom_printf(const char* format_string, ...) { va_list args; va_start(args, format_string); custom_vprintf(format_string, args); va_end(args); } int main(int argc, char** argv) { custom_printf("%s and %s\n", "foo", "bar"); return 0; }
Variadic macros provide an alternative approach to chaining variadic function calls.
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
All the tokens in the argument list after the last named argument become the 'variable argument' — this string is used to replace __VA_ARGS__
wherever it appears in the macro body.
At least one argument is required in place of the ellipsis in calls to the macro.