这是一个相关的例子。它显然不是有效的 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的编译器不应该只是在宏扩展期间插入额外的空格,因为它可能会阻止编程错误。
答案 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:宏观扩张和指令处理”。