在C宏扩展期间,宏的特殊情况是否会扩展为“/ *”?

时间:2010-11-12 13:50:52

标签: c macros c-preprocessor c99

这是一个相关的例子。它显然不是有效的 C ,但我只是在这里处理预处理器,所以代码实际上不需要编译。

#define IDENTITY(x) x
#define PREPEND_ASTERISK(x) *x
#define PREPEND_SLASH(x) /x

IDENTITY(literal)
PREPEND_ASTERISK(literal)
PREPEND_SLASH(literal)
IDENTITY(*pointer)
PREPEND_ASTERISK(*pointer)
PREPEND_SLASH(*pointer)

在其上运行gcc的预处理器:

gcc -std=c99 -E macrotest.c

这会产生:

(...)

literal
*literal
/literal
*pointer
**pointer
/ *pointer

请注意最后一行的额外空格。

这看起来像是一个阻止宏扩展到“/ *”的功能,我确信这是善意的。但是一目了然,我在C99标准中找不到任何与此行为有关的内容。然后,我对 C 缺乏经验。有人可以对此有所了解吗?这指定在哪里?我猜想一个坚持C99的编译器不应该只是在宏扩展期间插入额外的空格,因为它可能会阻止编程错误。

2 个答案:

答案 0 :(得分:15)

源代码在被CPP处理之前已经被标记化。

所以你拥有的是/*令牌,它不会隐式地合并到/*“令牌”(因为/ *实际上不是我放置的预处理器令牌)它在“”)。

如果使用-E输出预处理的源CPP,则需要插入空格以避免后续编译器传递读取/*

相同的功能可防止两个例如来自不同宏的+符号在输出中合并为++标记。

将两个预处理程序标记真正粘贴在一起的唯一方法是使用##运算符:

#define P(x,y) x##y

...

P(foo,bar)   

会产生令牌foobar

P(+,+)

会产生令牌++,但

P(/,*)       

无效,因为/*不是有效的预处理程序令牌。

答案 1 :(得分:5)

预处理器的行为是标准化的。在http://en.wikipedia.org/wiki/C_preprocessor的摘要中,您观察到的结果是:

的效果

“3:标记化 - 预处理器将结果分解为预处理标记和空格。它用空格替换注释”。

这发生在:

之前

“4:宏观扩张和指令处理”。