请问C预处理器剥去意见或先展开宏? [重复](Does the C preprocessor s

2019-07-20 15:29发布

这个问题已经在这里有一个答案:

  • 在其编译的步骤中去除评论? 2个回答

考虑这个(太可怕了,太可怕了,没有好,非常糟糕的)代码结构:

#define foo(x) // commented out debugging code

// Misformatted to not obscure the point
if (a)
foo(a);
bar(a);

我见过两个编译预处理程序生成的验证码不同的结果:

if (a)
bar(a);

if (a)
;
bar(a);

显然,这是一个可移植的代码基础一件坏事。

我的问题:什么是应该用这个做预处理? 第一评论的Elid,或首先展开宏?

Answer 1:

不幸的是,原来的ANSI C规范明确排除在第4任何预处理器的功能(“本说明书仅描述了C语言,它使没有规定任何库或预处理器”)。

该C99规范处理此明确地,虽然。 该意见被替换为“翻译阶段”一个单一的空间,其中预处理指令解析之前发生。 (第6.10节的详细信息)。

VC ++和GNU C编译器都遵循此模式-如果他们年长其他编译器可能不兼容的,但如果它的C99兼容的,你应该是安全的。



Answer 2:

正如在描述这个副本正粘贴能解密在C99标准翻译阶段,删除注释(它们由单个空格置换)发生在翻译阶段3,而预处理指令的处理和宏在相位4中展开。

在C90标准(我只在硬拷贝,所以没有抄正膏)这两个阶段发生在相同的顺序,虽然转换阶段的描述是C99标准的一些细节略有不同 - 事实上该评论被删除,预处理指令之前,由单一的空白字符替换的处理和扩大宏是没有什么不同。

同样,C ++标准具有发生在相同的顺序这2个相。

至于如何“ // ”意见应该如何处理,C99标准说,这(6.4.9 / 2):

除了一个字符内是恒定的,字符串文字或注释,字符//引入一个注释,包括所有多字节字符最多,但不包括下一个新行字符。

和C ++标准说(2.7):

字符//开始一个注释,与下一个换行符终止。

所以,你的第一个例子显然是对翻译的部分错误-在“ ; '后字符foo(a)应当保留当foo()宏展开-注释字符不应该的一部分‘的内容’ the foo()的宏。

但是,因为你面对的是一个越野车的翻译,你可能要改变宏定义:

#define foo(x) /* junk */

要解决的bug。

但是,(我在这里漂流题外话......),因为线拼接(反斜线只是一个新的行前)出现意见进行处理之前,你可以碰到这样的事情有点讨厌的代码:

#define evil( x) printf( "hello "); // hi there, \
                 printf( "%s\n", x); // you!



int main( int argc, char** argv)
{
    evil( "bastard");

    return 0;
}

这可能会惊讶谁写的。

甚至更好,尝试以下方法,由某人写的(当然不是我!)谁喜欢箱体式的评论:

int main( int argc, char** argv)
{
                            //----------------/
    printf( "hello ");      // Hey, what the??/
    printf( "%s\n", "you"); // heck??         /
                            //----------------/
    return 0;
}

根据是否你的编译器的默认处理三合与否(编译器都应该,但由于三合惊喜几乎每个人都谁碰到他们运行,一些编译器决定在默认情况下将其关闭),你可能会或可能不会得到你想要的行为-什么行为是的,当然。



Answer 3:

根据MSDN ,注释替换为标记化阶段的单一空间,在预处理阶段,其中宏展开之前恰好。



Answer 4:

永远不要把//评论在您的宏。 如果你必须把注释,使用/ * * /。 此外,你在你的宏错误:

#define foo(x) do { } while(0) /* junk */

这样一来,foo是永远放心使用。 例如:

if (some condition)
    foo(x);

不会抛出一个编译错误不管FOO是否被定义为一些表达。



Answer 5:

#ifdef _TEST_
#define _cerr cerr
#else
#define _cerr / ## / cerr
#endif
  • 将一些编译器(VC ++)工作。 当_TEST_没有定义,

    _cerr ...

    将被注释行被替换

    // CERR ...



Answer 6:

我似乎记得,合规性需要三个步骤:

  1. 跳闸
  2. 扩展宏
  3. 再次剥离

这样做的原因有编译器能够直接接受。我的文件做。



文章来源: Does the C preprocessor strip comments or expand macros first? [duplicate]