behavior of variadic macro

L

Laurent Deniau

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*
A(x) -> x

B() -> nothing, *warning ISO C99 requires rest arguments to be used*
B(x) -> nothing, *warning ISO C99 requires rest arguments to be used*
B(x,y) -> y

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?

a+, ld.
 
G

Guest

Laurent said:
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())

Similarly, you could write
B(x,)
which would behave as
B(x,EMPTY())
but not
B(x)

(In the general case, you cannot tell from a macro invocation how many
arguments are passed without seeing its definition. For EMPTY(), in the
above examples, no arguments are passed.)
 
L

Laurent Deniau

Harald said:
Laurent said:
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.
Similarly, you could write
B(x,)
which would behave as
B(x,EMPTY())

this is not consistent with what gcc says (and where I agree with it):

#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 */
B(x,E()) -> /* nothing, no warning, OK */
B(x,y) -> y

OK means I agree with the behavior (including the diagnostic) while ??
means that I am expecting the diagnostic of the constraint violation.
(In the general case, you cannot tell from a macro invocation how many
arguments are passed without seeing its definition.

Strange, I have a macro which returns the number of arguments received
by a macro from 0 to N if N < 64.

a+, ld.
 
G

Guest

Laurent said:
Harald said:
Laurent said:
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.
B(x,E()) -> /* nothing, no warning, OK */
B(x,y) -> y

OK means I agree with the behavior (including the diagnostic) while ??
means that I am expecting the diagnostic of the constraint violation.


Strange, I have a macro which returns the number of arguments received
by a macro from 0 to N if N < 64.

I'd like to see it. Does it handle the case of 0 specially by actually
testing to see if the argument is empty?
 
L

Laurent Deniau

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
 
G

Guest

Laurent said:
Harald said:
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. [...]

So it would report that NARGS(EMPTY()) == 0, would it not? That may be
a good thing, depending on how NARGS is intended to be used, but it
doesn't return the number of arguments received. :)
 
L

Laurent Deniau

Harald said:
Laurent said:
Harald said:
Laurent Deniau wrote:

Strange, I have a macro which returns the number of arguments received
by a macro from 0 to N if N < 64.

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. [...]


So it would report that NARGS(EMPTY()) == 0, would it not?

Yes it does, and it is the goal. The difficult part was to know if the
macro received an empty argument or a single argument since both are
counted as *one* argument by cpp.
That may be
a good thing, depending on how NARGS is intended to be used, but it
doesn't return the number of arguments received. :)

Right, this is the goal of FPP_NARG used by FPP_LEN on the right side of
the FPP_IF. FPP_LEN must return 0 for an empty list. Returning the
number of arguments received is much simpler, since the following is enough:

#define NUM_ARGS(...) \
FPP_NARG(__VA_ARGS__)

NUM_ARGS() -> 1
NUM_ARGS(()) -> 1
NUM_ARGS(a) -> 1
NUM_ARGS(a,b) -> 2
NUM_ARGS(FPP_EMPTY()) -> 1

a+, ld.
 
R

Richard Bos

Laurent Deniau said:
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*
A(x) -> x

B() -> nothing, *warning ISO C99 requires rest arguments to be used*
B(x) -> nothing, *warning ISO C99 requires rest arguments to be used*
B(x,y) -> y

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?

No. I suspect this is because of a previous, conflicting GCC use of ...
for variable macro arguments, BICBW.

What happens if you call B(x,)?

Richard
 
L

Laurent Deniau

Richard said:
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*
A(x) -> x

B() -> nothing, *warning ISO C99 requires rest arguments to be used*
B(x) -> nothing, *warning ISO C99 requires rest arguments to be used*
B(x,y) -> y

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?


No. I suspect this is because of a previous, conflicting GCC use of ...
for variable macro arguments, BICBW.

Harald Van Djik has perfectly pointed out the problem. I did a stupid
mistake while counting arguments of a macro invocation.
What happens if you call B(x,)?

no warning, as expected since the second argument is provided.

a+, ld.
 
L

Laurent Deniau

Harald said:
Laurent said:
Harald said:
Laurent Deniau wrote:

Strange, I have a macro which returns the number of arguments received
by a macro from 0 to N if N < 64.

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. [...]


So it would report that NARGS(EMPTY()) == 0, would it not? That may be
a good thing, depending on how NARGS is intended to be used, but it
doesn't return the number of arguments received. :)

In fact, I just discovered a problem in the macro (already mentionned in
my previous post):

#define FPP_ISEMPTY_(a) \
FPP_AND(FPP_ISLIST(a ()),FPP_NOT(FPP_ISLIST(a)))

Which evaluates a() if a() is a defined function-like macro. And I do
not find a way to prevent its evaluation in ISLIST. Any idea/clue?

a+, ld.
 
L

Laurent Deniau

Laurent said:
In fact, I just discovered a problem in the macro (already mentionned in
my previous post):

#define FPP_ISEMPTY_(...) \
FPP_AND(FPP_ISLIST(__VA_ARGS__ ()),FPP_NOT(FPP_ISLIST(__VA_ARGS__)))

Which evaluates x() if __VA_ARGS__ ends with a function-like macro x. And I do
not find a way to prevent this evaluation in ISLIST. Any idea/clue?

I reply to myself and add a new question...

In fact, it seems there is no way to prevent the evaluation of x() and
still allow the evaluation of FPP_ISLIST_TST_() (from ISLIST). So two
form of ISEMPTY should be provided, one for anything except
function-like macro and one for token which would include function-like
macro. Since the latter is less common, I keep the original design and
let the user to rely on NARG for function-like macro as argument where
usually empty argument is not useful (list of function to invoke).

BTW, I just discovered order-pp and chaos-pp on sourceforge.net and the
latter seems to have the same problem AFAIU from the source code (I
haven't found yet where to look at for order-pp).

I would be very happy if somebody could tell me where to find the
documentations of these libraries (not on CVS) and their future plans.
Or are they private/copyrighted (books in preparation?)?

a+, ld.
 
P

Paul Mensonides

Laurent said:
In fact, it seems there is no way to prevent the evaluation of x() and
still allow the evaluation of FPP_ISLIST_TST_() (from ISLIST). So two
form of ISEMPTY should be provided, one for anything except
function-like macro and one for token which would include
function-like macro. Since the latter is less common, I keep the original
design and
let the user to rely on NARG for function-like macro as argument where
usually empty argument is not useful (list of function to invoke).

There is no way to detect emptiness in general. The only way to do it is to
restrict input. There are various ways to do it with various restrictions, but
no one-size-fits-all solution.

Regarding counting arguments... If you have a macro defined as:

#define A(...) // ...

Then the number or arguments is *always* at least one. There is no such thing
zero arguments for a macro defined this way. If you pass nothing, such as:

A()

It simply means that you are passing a placemarker as the one and only argument.
Similarly:

A(,)

Here you are passing a placemarker for the first and second arguments. Thus,
the invocations A() and A(1) are both unary invocations of the variadic macro A,
and the invocations A(,) and A(1,2) are both binary invocations of the variadic
macro A. The same is true for a macro defined as unary:

#define B(x) // ...

B() // unary invocation with x -> placemarker

Moreover, "nothing" (i.e. a placemarker) is a perfectly valid form of data to
pass as an argument.
BTW, I just discovered order-pp and chaos-pp on sourceforge.net and
the latter seems to have the same problem AFAIU from the source code (I
haven't found yet where to look at for order-pp).

The documentation for CHAOS_PP_IS_EMPTY_NON_FUNCTION says:

If __VA_ARGS__ is empty, this macro expands to 1. Otherwise, it expands to 0.

Though this macro is a general purpose macro (unlike CHAOS_PP_IS_EMPTY), it is
not a complete solution to emptiness detection. Specifically, __VA_ARGS__ may
not terminate with the name of a function-like macro:

#define FUNC() /* ... */

CHAOS_PP_IS_EMPTY_NON_FUNCTION(FUNC) // invalid

(Full-fledged detection of emptiness is not possible without well-defined
token-pasting semantics when token-pasting does not yield a single preprocessing
token.)

[end-quote]
I would be very happy if somebody could tell me where to find the
documentations of these libraries (not on CVS) and their future plans.
Or are they private/copyrighted (books in preparation?)?

The documentation for Chaos is in the CVS, but it isn't built. I'm in the
process of rewriting some of the library (including some of the documentation
and adding automating regression testing). The CVS is not 100% current because
of that. However, I can send you a package containing a complete build of the
documentation as of the current CVS if you'd like.

Both Order and Chaos are published under the Boost Software License. The Order
library is no longer actively maintained, and I'm not extremely familiar with
it.

Regards,
Paul Mensonides
 
L

Laurent Deniau

Paul said:
Laurent Deniau wrote:




There is no way to detect emptiness in general. The only way to do it is to
restrict input. There are various ways to do it with various restrictions, but
no one-size-fits-all solution.

Regarding counting arguments... If you have a macro defined as:

#define A(...) // ...

Then the number or arguments is *always* at least one. There is no such thing
zero arguments for a macro defined this way. If you pass nothing, such as:

A()

It simply means that you are passing a placemarker as the one and only argument.

Right. I should have said something like "effective argument" or
"non-empty argument".
Similarly:

A(,)

As I said, I correctly counted 2 arguments for this invocation while I
counted "zero" argument for an invocation like A(). A minimum of logic
would have led to 2-1 = 1, not 0 and therefore 1 argument for A(), but I
think I was a bit tired the day of my OP.
BTW, I just discovered order-pp and chaos-pp on sourceforge.net and
the latter seems to have the same problem AFAIU from the source code (I
haven't found yet where to look at for order-pp).


The documentation for CHAOS_PP_IS_EMPTY_NON_FUNCTION says:

If __VA_ARGS__ is empty, this macro expands to 1. Otherwise, it expands to 0.

Though this macro is a general purpose macro (unlike CHAOS_PP_IS_EMPTY), it is
not a complete solution to emptiness detection. Specifically, __VA_ARGS__ may
not terminate with the name of a function-like macro:

#define FUNC() /* ... */

CHAOS_PP_IS_EMPTY_NON_FUNCTION(FUNC) // invalid

(Full-fledged detection of emptiness is not possible without well-defined
token-pasting semantics when token-pasting does not yield a single preprocessing
token.)

[end-quote]

I would be very happy if somebody could tell me where to find the
documentations of these libraries (not on CVS) and their future plans.
Or are they private/copyrighted (books in preparation?)?


The documentation for Chaos is in the CVS, but it isn't built.

Yes, I saw the xml files.
I'm in the
process of rewriting some of the library (including some of the documentation
and adding automating regression testing). The CVS is not 100% current because
of that. However, I can send you a package containing a complete build of the
documentation as of the current CVS if you'd like.

It would be very nice since it took me some time to go through all the
files involved in the macros I was interested in (the one you cited above).
Both Order and Chaos are published under the Boost Software License. The Order
library is no longer actively maintained, and I'm not extremely familiar with
it.

Ok. Thanks for your reply.

BTW, I will put my small fpp-lib (fpp stands for functional cpp) on the
web soon and I will be very happy if you could take some time to have a
look and give me some feedback. I did it from scratch so I am pretty
sure that a lot of improvement can be addressed by experienced cpp
programmers. I am specially interested by light-weight (I even need only
a small subset of fpp), efficiency and cpp99 portability (sic!). In fact
fpp is not my topic of interest, but I need it to generate OO C code. It
is possible that once choas is ready and fast, I will switch to it. But
for now, chaos appears to me as something huge.

Regards,

Laurent.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top