In Visual Studio 2008 (without SP1), I can compile and run this code
// vcconsole.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#define NOERROR
#ifdef /*
*/ NOERROR
void pr() {
printf("hello world..\n");
}
#endif
int _tmain(int argc, _TCHAR* argv[])
{
pr();
return 0;
}
But if I manually replace the block comment with spaces :
// vcconsole.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#define NOERROR
#ifdef
NOERROR
void pr() {
printf("hello world..\n");
}
#endif
int _tmain(int argc, _TCHAR* argv[])
{
pr();
return 0;
}
it fails to compile with error:
1>------ Build started: Project: vcconsole, Configuration: Debug Win32 ------
1>Compiling...
1>vcconsole.cpp
1>c:\x64\winproj\vcconsole\vcconsole.cpp(6) : fatal error C1016: #if[n]def expected an identifier
1>Build log was saved at "file://c:\x64\winproj\vcconsole\Debug\BuildLog.htm"
1>vcconsole - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Why the 2 are not equivalent?
This concerns me because I am using a tool to remove all comments from my c++ source code (I need to do this for other reasons) before compiling them. If the 2 are not equivalent somehow, my tool may fail.
There’s something in the Standard like a comment is replaced by a single space… that effectively removes the newlines. Your tool should do the same.
Note that under [lex.parses] 2.1.1.3 “Each comment is replaced by one space character.” before 2.1.1.4 “Preprocessing directives are executed and macro invocations are expanded.”.
As unquiet mind observes, a preprocessor directive only extends from the introductory preprocessor token through to the next newline, so you can’t put the symbol on a subsequent line (unless you use backslash escapes to effectively combine lines in an early parsing phase).
So, my tentative explanation for Microsoft’s non-compliant preprocessing switch behaviour is: Visual C++ is doing something non-Standard in preserving newlines in comments (probably to help track line numbers), so it then needs to build in some tracking and tolerance for the consequent multi-line preprocessing directives, keeping them working. /P and /E output the non-Standard multi-line directives, but lose that tracking metadata that makes it compilable.