Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

__VA_NARG__

28,142 views
Skip to first unread message

Laurent Deniau

unread,
Jan 16, 2006, 12:43:40 PM1/16/06
to
Hi all,

A year ago, I was asking here for an equivalent of __VA_NARG__ which
would return the number of arguments contained in __VA_ARGS__ before its
expansion. In fact my problem at that time (detecting for a third
argument) was solved by the solution of P. Mensonides. But I was still
thinking that the standard should have provided such a facilities rather
easy to compute for cpp.

This morning I had to face again the same problem, that is knowing the
number of arguments contained in __VA_ARGS__ before its expansion (after
its expansion can always be achieved if you can do it before). I found a
simple non-iterative solution which may be of interest here as an answer
to who will ask in the future for a kind of __VA_NARG__ in the standard
and I post it for archiving. May be some more elegant-efficient solution
exists?

regards,

ld.


Returns NARG, the number of arguments contained in __VA_ARGS__ before
expansion as far as NARG is >0 and <64 (cpp limits):

#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,[..],_61,_62,_63,N,...) N
#define PP_RSEQ_N() 63,62,61,60,[..],9,8,7,6,5,4,3,2,1,0

[..] stands for the continuation of the sequence omitted here for
lisibility.

PP_NARG(A) -> 1
PP_NARG(A,B) -> 2
PP_NARG(A,B,C) -> 3
PP_NARG(A,B,C,D) -> 4
PP_NARG(A,B,C,D,E) -> 5
PP_NARG(A1,A2,[..],A62,A63) -> 63

Roland Illig

unread,
Jan 20, 2006, 6:58:41 AM1/20/06
to
Laurent Deniau wrote:
> This morning I had to face again the same problem, that is knowing the
> number of arguments contained in __VA_ARGS__ before its expansion (after
> its expansion can always be achieved if you can do it before). I found a
> simple non-iterative solution which may be of interest here as an answer
> to who will ask in the future for a kind of __VA_NARG__ in the standard
> and I post it for archiving. May be some more elegant-efficient solution
> exists?

Thanks for this idea. I really like it.

For those that only want to copy and paste it, here is the expanded version:

/* 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

/* Some test cases */


PP_NARG(A) -> 1
PP_NARG(A,B) -> 2
PP_NARG(A,B,C) -> 3
PP_NARG(A,B,C,D) -> 4
PP_NARG(A,B,C,D,E) -> 5

PP_NARG(1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3,4,5,6,7,8,9,0,
1,2,3) -> 63

Note: using PP_NARG() without arguments would violate 6.10.3p4 of ISO C99.

Laurent Deniau

unread,
Jan 20, 2006, 7:16:24 AM1/20/06
to

Right. I try to ensure that I always have at least one argument in my
macros which are expected to accept arguments (like for variadic functions).

Thanks for the pretty expanded version.

ld.

arpad.g...@gmail.com

unread,
Apr 22, 2012, 7:31:28 AM4/22/12
to
I extended this to also work correctly with 0 arguments (but now it will accept only 62 arguments):


#define __VA_NARG__(...) \
(__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) - 1)
#define __VA_NARG_(...) \
__VA_ARG_N(__VA_ARGS__)
#define __VA_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 __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

Hope this helps.

Jens Gustedt

unread,
Apr 22, 2012, 12:10:53 PM4/22/12
to
Hello,
it seems that you are using the ``, ##'' extension of gcc to achieve
your goal. This is not standard, and so in particular this news group
is probably not appropriate.

There are other, more standard ways around this problem of detecting
if a va_arg macro is called with an empty argument. Unfortunately none
of them is completely error prone, but at least some are usably in
practise.

In that sense it would be really nice, I agree, if there would be a
standard functionality to achieve that goal. For the moment the
preprocessing phase doesn't foresee much of "meta" functions. So this
would be a substatial change of the pattern, not likely to happen.

Jens

zhangj...@gmail.com

unread,
Jan 29, 2015, 11:05:27 PM1/29/15
to
(__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()))
#define __VA_NARG_(...) \
__VA_ARG_N(__VA_ARGS__)
#define __VA_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 __RSEQ_N() \
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

we needn't add "-1" after __RSEQ_N(), only remove "63," in __RSEQ_N. that's OK

mad...@acm.org

unread,
Jan 30, 2015, 10:41:27 AM1/30/15
to
On Sunday, April 22, 2012 at 12:10:53 PM UTC-4, Jens Gustedt wrote:
> Hello,
> it seems that you are using the ``, ##'' extension of gcc to achieve
> your goal. This is not standard, and so in particular this news group
> is probably not appropriate.

> Jens

Actually the ## pasting operator is completely standard. See ISO/IEC 9899:1999(E) 6.10.3.3.

Randy.

Kaz Kylheku

unread,
Jan 30, 2015, 2:23:09 PM1/30/15
to
I don't see any claim that ## is not standard.

seshr...@gmail.com

unread,
Jan 31, 2015, 6:43:42 PM1/31/15
to
https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

According to this page the '##' operator has a special meaning in this context using GCC CPP.

Keith Thompson

unread,
Jan 31, 2015, 6:54:30 PM1/31/15
to
The post by Jens refers to ## following a comma, which is a gcc
(actually GNU cpp) extension. It's easy to miss the comma between the
`` and '' delimiters and assume he was saying that ## itself is an
extension.

In any case, the article was posted in 2012; it's likely this was
already covered at the time (I'm too lazy to go back and check).

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
0 new messages