How to count the number of arguments passed to a function that accepts a variable number of arguments?
Solution 1
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)
Solution 2
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.)
Solution 3
If you have a C99 compliant compiler (including the preprocessor) you can circumvent this problem by declaring a macro that computes the number of arguments for you. Doing this yourself is a bit tricky, you may use P99_VA_ARGS
from the P99 macro package to achieve this.
Solution 4
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)
Solution 5
You can't. varargs aren't designed to make this possible. You need to implement some other mechanism to tell the function how many arguments there are. One common choice is to pass a sentinel argument at the end of the parameter list, e.g.:
varfun(1, 2, 3, 4, 5, 6, -1);
Another is to pass the count at the beginning:
varfun(6, 1, 2, 3, 4, 5, 6);
This is cleaner, but not as safe, since it's easier to get the count wrong, or forget to update it, than it is to remember and maintain the sentinel at the end.
It's up to you how you do it (consider printf's model, in which the format string determines how many — and what type — of arguments there are).
codeomnitrix
Young | Enthusiastic | Ecstatic | Raw Programmer | Counter-Strike
Updated on September 04, 2021Comments
-
codeomnitrix over 2 years
How to count the no of arguments passed to the function in following program:
#include<stdio.h> #include<stdarg.h> void varfun(int i, ...); int main(){ varfun(1, 2, 3, 4, 5, 6); return 0; } void varfun(int n_args, ...){ va_list ap; int i, t; va_start(ap, n_args); for(i=0;t = va_arg(ap, int);i++){ printf("%d", t); } va_end(ap); }
This program's output over my gcc compiler under ubuntu 10.04:
234561345138032514932134513792
so how to find how many no. of arguments actually passed to the function?
-
Alexandre C. over 13 years@codeomnitrix: it's sad but true. As a rule of thumb, stay away from variable length arguments. Unless you do C++0x.
-
codeomnitrix over 13 yearsOk thanks, but much more beyond my c knowledge. I will try to understand this one
-
Matt Joiner over 13 yearsFor now, also stay away from C++0x. However the variadic templates in C++0x are really nice.
-
Alexandre C. over 13 years@Matt: With variadic templates you can also write type safe variadic functions.
-
Owl almost 6 yearsHow do you know that the next pointer is null? Or is it pointing to uninitialised memory?
-
Alexander over 5 yearsBeware that
printf("%%")
expects no arguments, though. -
Haroun Hajem almost 4 yearsEvery modern language has the ability to count a list except C++, what a shame.
-
Craig B over 3 years@HarounHajem, C++ is not a modern language as programming languages go. :)
-
user1742529 almost 3 yearsI checked your ways. Thank you! See comment to answer for details: stackoverflow.com/questions/1688942/…
-
SO Stinks almost 3 yearsI've been using NULL as a sentinel for a list of pointer arguments and it has worked for me but I've discovered that apparently in general this could result in undefined behavior because of how NULL is implemented in some architectures.
-
SO Stinks almost 3 yearsIt is my understanding that in standard C you cannot use NULL to terminate the argument list of a variadic function without risking undefined behavior so your second bullet point, while it might often work, is a bad choice. You basically must tell the function how many arguments there are, with your first and second bullet points being the only two feasible possibilities. Some compilers however have features that allow a NULL terminator like gcc which has
__attribute__((sentinel))
while other C-like language compilers have, for example,NS_REQUIRES_NIL_TERMINATION
. -
berhauz over 2 yearswhoever put me a negative quote on this answer has possibly not seen that after the traditional for loop that indeed doesn't provide any direct count, the initializer list allows using: elts.size() that perfectly answers the question.