Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between gcc and Microsoft preprocessor

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?

like image 608
Sergey Syromyatnikov Avatar asked Jul 13 '12 11:07

Sergey Syromyatnikov


People also ask

Is gcc a preprocessor?

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.

What is difference between preprocessor and macros?

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.

What is GNU preprocessor?

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.


2 Answers

# 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.

like image 176
Sebastian Mach Avatar answered Oct 12 '22 00:10

Sebastian Mach


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
like image 24
SingerOfTheFall Avatar answered Oct 12 '22 01:10

SingerOfTheFall