tags:

views:

115

answers:

3

When using va_start(), va_arg() and va_end() to read parameters passed to a method, is there a way to count how many arguments there are?

According to the man page if you call va_arg() too many times you get "random errors":

If there is no next argument, or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), random errors will occur.

+7  A: 

No. a Variable Argument function (such as printf), must "know" when to stop looking for more arguments.

printf knows by the number of %d, %s and other symbols in its format string.

Other functions sometimes use Sentinel values:

sumValues(1, 3, 5, 7, 6, 9, -1); // will add numbers until it encounters a -1

Other functions may have the number of parameters stated up front:

AddNames(4, "Bill", "Alice", "Mike", "Tom");
abelenky
+5  A: 

There are two ways to know how many arguments were passed. First, you can have one of the function parameters tell you (like printf for example). The other way is to have a sentinel value at the end of your list - for instance, you could stop at a NULL argument.

You can use va_copy if you choose the second method, but still want to count the parameters before deciding what to do with them.

Carl Norum
+6  A: 

Here is a fairly astonishing trick that allows you to build what you want using C99's variadic macros:

PP_NARG()
Returns the number of arguments contained in __VA_ARGS__

You can use this to write a macro wrapping your real function that adds a count to the front of the real function's arguments.

See also this question. However probably the classical approaches are still more sensible for a year or three yet!


The code, so that this answer is useful even without the Usenet archive...

/* The PP_NARG macro returns the number of arguments that have been
  * passed to it.
  */

#define PP_NARG(...) \
         PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
         PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
          _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,N,...) N
#define PP_RSEQ_N() \
         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 
John Marshall
I should say this is lovely :-) Nice finding!
jweyrich
Exactly what I'm going to say!
Nyan
P99 will have a set of macros inspired by that and which could be exactly what you need. Unfortunately the release will only be in some week time, but if you want to have a look in the documentation: http://p99.gforge.inria.fr/p99-html/group__variadic.html
Jens Gustedt
@Jens: at a glance, the P99 documentation looks interesting and all, but I rather lost interest in reading further when I got to this bit: "This file is part of the P99 project. You received this file as as part of a confidential agreement and you may generally not redistribute it and/or modify it, unless under the terms as given in the file LICENSE." There was no confidential agreement, there is no LICENSE file to be found on the documentation website, and I am generally uninterested in things I cannot tinker with.
John Marshall
@John: I agree completely. This license will change and is actually the reason why the P99 is not yet released: I am in discussion with my hierarchy of which license to choose. Probably it will be something like LGPL. But procedures are slow, here in France.
Jens Gustedt
@Jens: Fair enough, that discussion is hardly ever fun. Complaint withdrawn :-)
John Marshall