C preprocessor problem in Microsoft Visual Studio 2010
I've encountered a problem with the new Visual C++ in VS 2010.
I've got a header with the following defines:
#define STC(y) #y
#define STR(y) STC(\y)
#define NNN(y) 0##y
#define NUM(y) NNN(y)
The intent is that you can have some constant around like
#define TOKEN x5A
and then you can have the token as a number or as a string:
NUM(TOKEN) -> 0x5A
STR(TOKEN) -> "\x5A"
This is the expected behavior under the the substitution rules of macros arguments and so far it has worked well with gcc, open watcom, pellesC (lcc), Digital Mars C and Visual C++ in VS2008 Express.
Today I recompiled the library with VS2010 Express only to discover that it doesn't work anymore! Using the new version I would get:
NUM(TOKEN) -> 0x5A
STR(TOKEN) -> "\y"
It seems that the new preprocessor treats \y
as an escape sequence even within a macro body which is a non-sense as escape sequences only have a meaning in literal strings.
I suspect this is a gray area of the ANSI standard but even if the original behavior was mandated by the standard, MS VC++ is not exactly famous to be 100% ANSI C compliant so I guess I'll have to live with the new behavior of the MS compiler.
Given that, does anybody have a suggestion on how to re-implement the original macros behavior with VS2010?
EDIT: Corrected the NUM()
macro
EDIT: Possible solution
I think I've found a way to do it:
#define STC(y) #y
#if defined(_MSC_VER) && (_MSC_VER >= 开发者_JAVA技巧1600)
#define STA(x,y) STC(x##y)
#define STR(y) STA(\,y)
#else
#define STR(y) STC(\y)
#endif
#define NNN(y) 0##y
#define NUM(y) NNN(y)
Now I get:
#define TOKEN x2E
NUM(TOKEN) -> 0x2E
STR(TOKEN) -> "\x2E"
Of course gcc complains about joining a backslash to a literal (\ ## x2E
) because the result is not a valid preprocessor symbol but MS seems happy, hence the #ifdef
.
I'll be happy to hear if anyone has a better solution!
You are/were relying on some weird non-standard behavior of the compiler.
Your NUM
macro is written incorrectly. It should have never worked, neither in the old nor in the new version of the compiler. When you do NUM(TOKEN)
the result of the macro expansion in any standard-compliant compiler will be 0TOKEN
and not 0x5A
. In order to make your NUM
macro work as intended you have to implement it in two-level fashion:
#define NUM_(y) 0##y
#define NUM(y) NUM_(y)
The only reason it "worked" for you so far is just another glitch in the compiler.
I'm not sure yet what's happening with the STR
case. The compiler is indeed complaining about an unrecognized escape sequence. Must be a bug in the compiler.
If you use
#define STR(y) STC(\\y)
then it works for me with VS2010.
I think this is the correct definition for STR(y). Worked in a test program under gcc, and appears to use normal macro methods.
#define STC(y) #y
#define STR(y) "\\" STC(y)
MSVC is not a C compiler, it is a C++ compiler. The C compiler doesn't even offer some C99 features, and it's not intended to be a competitive modern C compiler.
I'm also going to question your use of the preprocessor in this way - it seems more than a little OTT to me.
精彩评论