Harald said:
Laurent said:
Harald said:
Laurent Deniau wrote:
I was playing a bit with the preprocessor of gcc (4.1.1). The following
macros expand to:
#define A(...) __VA_ARGS__
#define B(x,...) __VA_ARGS__
A() -> nothing, *no warning*
[...]
While I agree with the behavior of gcc on the uses of B(), I feel a bit
confused by its behavior on A() where I was expecting the same warning
as for B() according to ISO C99 6.10.3p4:
[...]
there shall be more arguments in the invocation than there are
parameters in the macro definition (excluding the ...)
Does this "more arguments" apply only if at least one argument
(excluding the ...) is required?
You gave A() an argument. That argument was empty. It behaves as if you
had written
#define EMPTY() /* nothing */
#define A(...) __VA_ARGS__
#define B(x,...) __VA_ARGS__
A(EMPTY())
AFAIK, A(EMPTY()) provides an argument to A which expands to nothing
which is quite different to A() which does not give an argument to A.
That may have been the case in C90 (from what I recall, it wasn't
particularly clear on the subject), but it isn't the case in C99, which
you are using if you're using variadic macros.
this is not consistent with what gcc says (and where I agree with it):
It is.
#define E() /* nothing */
A() -> /* nothing, no warning, ?? */
A(E()) -> /* nothing, no warning, OK */
A(x) -> x
B() -> /* nothing, warning, OK */
B(E()) -> /* nothing, warning, OK */
B(x) -> /* nothing, warning, OK */
You're using B(x) instead of B(x,) here. There's a difference.
Right. I get your point and I understand (now) that a macro is never
invoked with zero argument, but with at least one (which can obviously
be empty). My misunderstanding was not on macro replacement but on
argument counting. It was as stupid as 2-1 = 0! (where ! is not
factorial otherwise it would have been correct ;-) )
I'd like to see it. Does it handle the case of 0 specially by actually
testing to see if the argument is empty?
Yes. Here is an example macro NUM_ARGS which "returns" the number of
arguments it receives. I posted FPP_NARG on c.s.c some months ago and
show below the non-trivial macros involved in FPP_LEN (I can provide the
trival ones if it matters). I will probably make my FPP-lib public in a
couple of weeks if I find the time to finalize it. It is a light-weight
lib (~250 macros) which implements some common FPL idioms like map,
filter, foldl, foldr, ... on lists in C99. Nothing comparable to Boost
pp-lib.
#define NUM_ARGS(...) \
FPP_LEN((__VA_ARGS__))
// return length of list L
#define FPP_LEN(L) \
FPP_IF(FPP_ISEMPTY(L),0 FPP_EAT,FPP_NARG) L
// return 1 if the list L is empty, i.e. FPP_NIL() or ()
// return 0 otherwise
#define FPP_ISEMPTY(L) \
FPP_ISEMPTY_(FPP_1ST L)
// return 1 if its *first* argument is/starts-with a list
// return 0 otherwise
#define FPP_ISLIST(...) \
FPP_PAIR(FPP_1ST, \
(FPP_CATV(FPP_ISLIST_RET_, FPP_ISLIST_TST_ __VA_ARGS__)))
// --- implementation details ---
#define FPP_ISEMPTY_(a) \
FPP_AND(FPP_ISLIST(a ()),FPP_NOT(FPP_ISLIST(a _)))
#define FPP_ISLIST_TST_(...) 1
#define FPP_ISLIST_RET_FPP_ISLIST_TST_ 0,
#define FPP_ISLIST_RET_1 1,
Examples:
NUM_ARGS() -> 0
NUM_ARGS(()) -> 1
NUM_ARGS(a) -> 1
NUM_ARGS(a,b) -> 2
NUM_ARGS(a,b,c) -> 3
NUM_ARGS((a),b,c) -> 3
NUM_ARGS((a),(b),c) -> 3
NUM_ARGS(((a),(b)),c) -> 2