You can see the NARGS macro
Adapted to your code:
#include <stdio.h> #include <stdarg.h> #define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N #define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1) #define print(...) fnprint(NARGS(__VA_ARGS__), __VA_ARGS__) void fnprint(int n, ...) { va_list ap; int num; va_start(ap, n); while (n--) { num = va_arg(ap, int); printf("%d\n", num); } va_end(ap); return; } int main(void) { print(1, 2, 3, 4, 5); return 0; }
EDIT: If you want to use the same name for a macro and a function, use () to stop the preprocessor from expanding the function definition:
#define print(...) print(NARGS(__VA_ARGS__), __VA_ARGS__) void (print)(int n, ...) /* Note () around the function name */ { ...
EDIT 2: Another (ugly) method (but without limiting the number of arguments) using compound literals (std 99) and sizeof :
#include <stdio.h> #include <stdarg.h> #define print(...) print(sizeof((int []) {__VA_ARGS__}) / sizeof(int), __VA_ARGS__) void (print)(int n, ...) { va_list ap; int num; va_start(ap, n); while (n--) { num = va_arg(ap, int); printf("%d\n", num); } va_end(ap); return; } int main(void) { print(1, 2, 3, 4, 5); return 0; }
print expands to:
print(sizeof((int []) {1, 2, 3, 4, 5}) / sizeof(int), 1, 2, 3, 4, 5);
But constructions of type print(1, 2, 3, a_var++, 4, 5); or print(1, 2, some_func_returning_int(), 4, 5); evaluate a_var++ and some_func_returning_int() twice, this is a big problem.