Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One more difference between gcc's and MS preprocessor

One more difference between gcc preprocessor and that of MS VS cl. Consider the following snippet:

# define A(x) L ## x
# define B A("b")
# define C(x) x
C(A("a" B))

For 'gcc -E' we get the following:

L"a" A("b")

For 'cl /E' the output is different:

L"a" L"b"

MS preprocessor somehow performs an additional macro expansion. Algorithm of its work is obviously different from that of gcc, but this algorithm also seems to be a secret. Does anyone know how the observed difference can be explained and what is the scheme of preprocessing in MS cl?

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

Sergey Syromyatnikov


2 Answers

GCC is correct. The standard specifies:

C99 6.10.3.4/2 (and also C++98/11 16.3.4/2): 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.

So, when expanding A("a" B), we first replace B to give A("a" A("B")).

A("B") is not replaced, according to the quoted rule, so the final result is L"a" A("B").

like image 105
Mike Seymour Avatar answered Dec 12 '22 19:12

Mike Seymour


Mike's answer is correct, but he actually elides the critical part of the standard that shows why this is so:

6.10.3.4/2 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.

Note the last clause here that I've emphasized.

So both gcc and MSVC expand the macro A("a" B) to L"a" A("b"), but the interesting case (where MSVC screws up) is when the macro is wrapped by the C macro.

When expanding the C macro, its argument is first examined for macros to expand and A is expanded. This is then substituted into the body of C, and then that body is then scanned AGAIN for macros to replace. Now you might think that since this is the expansion of C, only the name C will be skipped, but this last clause means that the tokens from the expansion of A will also skip reexpansions of A.

like image 21
Chris Dodd Avatar answered Dec 12 '22 21:12

Chris Dodd