I discovered that Microsoft Visual Studio compiler and gcc preprocess the following small snippet differently:
# define M3(x, y, z) x + y + z
# define M2(x, y) M3(x, y)
# define P(x, y) {x, y}
# define M(x, y) M2(x, P(x, y))
M(a, b)
'gcc -E' gives the following:
a + {a + b}
, while 'cl /E' issues a warning about missing macro argument and produces the following output:
a + {a, b} +
It seems that commas that came from nested macro expansions are not considered to be argument separators. Unfortunately, I found no description of the algorithm implemented in cl preprocessor, and so I'm not sure that my suggestion is correct. Does anyone know how cl preprocessor works and what's the difference between its algorithm and gcc's? And how the observed behaviour can be explained?
In GCC, the preprocessor is actually integrated with the compiler rather than a separate program, and both of these commands invoke GCC and tell it to stop after the preprocessing phase. The cpp options listed here are also accepted by gcc and have the same meaning.
macros are name for fragment of code. A macro processor is a program that copies a stream of text from one place to another, making a systematic set of replacements as it does so. ... A preprocessor is a program that processes its input data to produce output that is used as input to another program.
This part of the documentation is a modified version of the GNU CPP Manual. Therefore it is licensed under the GNU Free Documentation License. The C preprocessor is a macro processor that is used automatically by the C compiler to transform your program before actual compilation.
# define M3(x, y, z) x + y + z
# define M2(x, y) M3(x, y)
# define P(x, y) {x, y}
# define M(x, y) M2(x, P(x, y))
M(a, b)
Let us roll this out manually, step by step:
M(a, b)
--> M2(a, P(a, b))
--> M2(a, {a, b})
The standard says:
The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate
only parentheses are mentioned, so ...
--> M3(a, {a, b})
--> a + {a + b}
Important:
M3(a, {a, b})
Here, according to the previous quote from the standard, three "arguments" are passed to M3 (using single-quotes to describe tokens/arguments):
M3('a', '{a', 'b}')
which are expanded to
'a' + '{a' + 'b}'
And this is what cpp
(4.6.1) gives verbatim:
# 1 "cpp.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpp.cpp"
a + {a + b}
cpp
(or gcc
and g++
) are correct, MSVC isn't.
As a nobleman make sure a bug report exists.
The only logic that explains such a behavior looks like this.
CL way:
M(a,b)
M2(a,P(a,b))
M3(a,P(a,b))
M3(a,{a,b}) -> M3 gets 2 arguments ( 'a' and '{a,b}') instead of 3.
| \ /
arg1 |
arg2
Gcc way:
M(a,b)
M2(a,P(a,b))
M3(a,P(a,b))
M3(a,{a,b}) -> Gcc probably thinks there are 3 arguments here ('a', '{a', 'b}').
| | |
arg1 | |
arg2 |
arg3
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