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

cur*_*mer 13 c macros c99 c-preprocessor

这是一个相关的例子.它显然不是有效的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)
Run Code Online (Sandbox Code Playgroud)

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

gcc -std=c99 -E macrotest.c
Run Code Online (Sandbox Code Playgroud)

这会产生:

(...)

literal
*literal
/literal
*pointer
**pointer
/ *pointer
Run Code Online (Sandbox Code Playgroud)

请注意最后一行的额外空间.

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

Pee*_*ger 15

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

所以你拥有的是一个/和一个*不会隐式组合成/*"令牌"的令牌(因为/*实际上并不是我把它放在""中的预处理器令牌).

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

相同的特征防止来自+不同宏的两个例如符号++在输出上被组合成令牌.

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

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

...

P(foo,bar)   
Run Code Online (Sandbox Code Playgroud)

导致令牌 foobar

P(+,+)
Run Code Online (Sandbox Code Playgroud)

导致令牌++,但是

P(/,*)       
Run Code Online (Sandbox Code Playgroud)

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

  • 很好的答案,虽然我有两个挑剔的评论:没有`/*`令牌; 在标记化之前,将从源中删除注释.你可以使用`##`从两个`+`标记形成一个`++`标记. (4认同)
  • BTW你不能粘贴/和*一起##你应该尝试它,因为##操作的结果必须是一个有效的预处理器令牌.正如你正确提到的那样/*不是预处理器令牌. (3认同)

Pas*_*uoq 5

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

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

这发生在:

"4:宏观扩张和指令处理".