Discussion:
__VA_NARG__
(too old to reply)
Laurent Deniau
2006-01-16 17:43:40 UTC
Permalink
Raw Message
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
2006-01-20 11:58:41 UTC
Permalink
Raw Message
Post by Laurent Deniau
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
2006-01-20 12:16:24 UTC
Permalink
Raw Message
Post by Roland Illig
Post by Laurent Deniau
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.
/* 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.
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.
a***@gmail.com
2012-04-22 11:31:28 UTC
Permalink
Raw Message
Post by Laurent Deniau
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
#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
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
2012-04-22 16:10:53 UTC
Permalink
Raw Message
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
m***@acm.org
2015-01-30 15:41:23 UTC
Permalink
Raw Message
Post by Jens Gustedt
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
2015-01-30 19:23:04 UTC
Permalink
Raw Message
Post by m***@acm.org
Post by Jens Gustedt
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.
I don't see any claim that ## is not standard.
s***@gmail.com
2015-01-31 23:43:40 UTC
Permalink
Raw Message
Post by Kaz Kylheku
Post by m***@acm.org
Post by Jens Gustedt
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.
I don't see any claim that ## is not standard.
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
2015-01-31 23:54:29 UTC
Permalink
Raw Message
Post by s***@gmail.com
Post by Kaz Kylheku
Post by m***@acm.org
Post by Jens Gustedt
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.
I don't see any claim that ## is not standard.
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.
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) kst-***@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"
z***@gmail.com
2015-01-30 04:05:25 UTC
Permalink
Raw Message
Post by a***@gmail.com
Post by Laurent Deniau
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
#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
#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.
#define __VA_NARG__(...) \
(__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
Loading...