在Visual Studio 2008(没有SP1)中,我可以编译并运行此代码
// 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;
}
但是如果我用空格手动替换块注释:
// 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;
}
无法编译错误:
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 ==========
为什么2不等同?
这让我很担心,因为我正在使用一个工具来删除我的c ++源代码中的所有注释(我出于其他原因需要这样做),然后再编译它们。如果2不相同,我的工具可能会失败。
答案 0 :(得分:3)
标准中有一些内容,例如注释被单个空格替换......有效地删除了换行符。你的工具也应该这样做。
请注意,在[lex.parses] 2.1.1.3下,“每个注释都被一个空格字符替换。”在2.1.1.4之前执行“预处理指令并扩展宏调用。”。
正如unquiet mind观察到的那样,预处理程序指令只从介绍性预处理程序令牌延伸到下一个换行符,因此您不能将该符号放在后续行上(除非您使用反斜杠转义符在早期解析中有效地组合行相)。
所以,我对微软不兼容的预处理切换行为的初步解释是:Visual C ++在保留评论中的换行符时做了非标准的事情(可能有助于跟踪行号),因此它需要构建一些跟踪和对随后的多行预处理指令的容忍度,使它们保持工作。 / P和/ E输出非标准多行指令,但丢失了可编辑的跟踪元数据。
答案 1 :(得分:2)
用空格替换会导致:
#ifdef NOERROR
但是,您替换为空格和换行符。预处理程序指令由换行符终止,就像C ++语句以分号结束一样。
答案 2 :(得分:2)
从标准,第16.1节
唯一的空白字符 应出现在一个预处理令牌之间 预处理指令(来自 在介绍#preprocessing之后 在之前的令牌 终止新行字符) 空格和水平标签(包括 已替换注释或可能包含其他空格的空格 翻译阶段的人物3)。
g ++也(正确地)无法编译代码。
答案 3 :(得分:1)
第一个有效,因为注释是注释,因此预处理器和编译器会忽略它。第二个不起作用,因为宏不能跨越多行,除非你将\
作为每行的最后一个字符。
如果要自动删除注释,但要避免使用预处理器,可以尝试首先运行预处理器,然后从预处理文件中删除注释,然后编译它们。