How to count the number of arguments passed to a function that accepts a variable number of arguments?
You can't. You have to manage for the caller to indicate the number of arguments somehow. You can:
- Pass the number of arguments as the first variable
- Require the last variable argument to be null, zero or whatever
- Have the first argument describe what is expected (eg. the printf format string dictates what arguments should follow)
You can let the preprocessor help you cheat using this strategy, stolen and tweaked from another answer:
#include <stdio.h>
#include <stdarg.h>
#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_128TH_ARG(__VA_ARGS__)
#define PP_128TH_ARG( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,_64,_65,_66,_67,_68,_69,_70, \
_71,_72,_73,_74,_75,_76,_77,_78,_79,_80, \
_81,_82,_83,_84,_85,_86,_87,_88,_89,_90, \
_91,_92,_93,_94,_95,_96,_97,_98,_99,_100, \
_101,_102,_103,_104,_105,_106,_107,_108,_109,_110, \
_111,_112,_113,_114,_115,_116,_117,_118,_119,_120, \
_121,_122,_123,_124,_125,_126,_127,N,...) N
#define PP_RSEQ_N() \
127,126,125,124,123,122,121,120, \
119,118,117,116,115,114,113,112,111,110, \
109,108,107,106,105,104,103,102,101,100, \
99,98,97,96,95,94,93,92,91,90, \
89,88,87,86,85,84,83,82,81,80, \
79,78,77,76,75,74,73,72,71,70, \
69,68,67,66,65,64,63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
void _variad(size_t argc, ...);
#define variad(...) _variad(PP_NARG(__VA_ARGS__), __VA_ARGS__)
void _variad(size_t argc, ...) {
va_list ap;
va_start(ap, argc);
for (int i = 0; i < argc; i++) {
printf("%d ", va_arg(ap, int));
}
printf("\n");
va_end(ap);
}
int main(int argc, char* argv[]) {
variad(2, 4, 6, 8, 10);
return 0;
}
There's a few clever tricks here.
1) Instead of calling the variadic function directly, you're calling a macro that counts the arguments and passes the argument count as the first argument to the function. The end result of the preprocessor on main looks like:
_variad(5, 2, 4, 6, 8, 10);
2) PP_NARG
is a clever macro to count arguments.
The workhorse here is PP_128TH_ARG
. It returns its 128th argument, by ignoring the first 127 arguments (named arbitrarily _1
_2
_3
etc.), naming the 128th argument N
, and defining the result of the macro to be N
.
PP_NARG
invokes PP_128TH_ARG
with __VA_ARGS__
concatenated with PP_RSEQ_N
, a reversed sequence of numbers counting from 127 down to 0.
If you provide no arguments, the 128th value of PP_RSEQ_N
is 0. If you pass one argument to PP_NARG
, then that argument will be passed to PP_128TH_ARG
as _1
; _2
will be 127, and the 128th argument to PP_128TH_ARG
will be 1. Thus, each argument in __VA_ARGS__
bumps PP_RSEQ_N
over by one, leaving the correct answer in the 128th slot.
(Apparently 127 arguments is the maximum C allows.)
You can't. Something else has to tell you (for instance for printf, it's implied by the number of % format descriptors in the format string)