It says in C++ std 16.3.4:
The resulting preprocessing token sequence [from a macro invocation replacement] is rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.
If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file’s preprocessing tokens), it is not replaced.
Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced.
These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.
What exactly is a nested macro replacement?
Specifically consider:
#define f(x) 1 x
#define g(x) 2 x
g(f)(g)(3)
I would have expected the following:
g(f)(g)(3) <-- first replacement of g, ok
2 f(g)(3) <-- nested replacement of f, ok
2 1 g(3) <-- second nested replacement of g, don't replace, stop
However gcc unexpectedly goes ahead with the second replacement of g, producing:
2 1 2 3
Any ideas?
Update:
After much research, let me clear up this issue with a simpler example:
#define A(x) B
#define B(x) A(x)
A(i)(j)
This expands as follows:
A(i)(j)
B(j)
A(j)
The standard does not specify whether A(j)
should be expanded to B
or not. The committee decided to leave it this way because real world programs are not expected to depend on this behavior, so both leaving A(j)
unexpanded and expanding A(j)
to B
are considered conformant.
A nested macro instruction definition is a macro instruction definition you can specify as a set of model statements in the body of an enclosing macro definition. This lets you create a macro definition by expanding the outer macro that contains the nested definition.
The C preprocessor and macros are one of the most useful elements for writing portable C/C++ code . It even can be used to completely different purposes, like text processing. However, it suffers one major drawback: it does not support nested macros expansion (put differently, macros within macros).
Nested macros are allowed.
This is called token pasting or token concatenation. The '##' pre-processing operator performs token pasting. When a macro is expanded, the two tokens on either side of each '##' operator are combined into a single token, which then replaces the '##' and the two original tokens in the macro expansion.
This explains the original intent, and why no clarifications have been added to the standard about this subject:
http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#268
268. Macro name suppression in rescanned replacement text
Section: 16.3.4 [cpp.rescan] Status: open Submitter: Bjarne Stroustrup Date: 18 Jan 2001
It is not clear from the Standard what the result of the following example should be:
#define NIL(xxx) xxx #define G_0(arg) NIL(G_1)(arg) #define G_1(arg) NIL(arg) G_0(42)
The relevant text from the Standard is found in 16.3.4 [cpp.rescan] paragraph 2:
[snipped]
The sequence of expansion of
G0(42)
is as follows:G0(42) NIL(G_1)(42) G_1(42) NIL(42)
The question is whether the use of
NIL
in the last line of this sequence qualifies for non-replacement under the cited text. If it does, the result will beNIL(42)
. If it does not, the result will be simply42
.The original intent of the J11 committee in this text was that the result should be
42
, as demonstrated by the original pseudo-code description of the replacement algorithm provided by Dave Prosser, its author. The English description, however, omits some of the subtleties of the pseudo-code and thus arguably gives an incorrect answer for this case.Suggested resolution (Mike Miller): [snipped]
Notes (via Tom Plum) from April, 2004 WG14 Meeting:
Back in the 1980's it was understood by several WG14 people that there were tiny differences between the "non-replacement" verbiage and the attempts to produce pseudo-code. The committee's decision was that no realistic programs "in the wild" would venture into this area, and trying to reduce the uncertainties is not worth the risk of changing conformance status of implementations or programs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With