在 C 宏扩展期间,宏是否存在扩展为“/*”的特殊情况?
这是一个相关的例子。它显然不是有效的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 的编译器不应该仅仅在宏扩展期间插入额外的空格,因为它可能会防止编程错误。
Here's a relevant example. It's obviously not valid C, but I'm just dealing with the preprocessor here, so the code doesn't actually have to compile.
#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)
Running gcc's preprocessor on it:
gcc -std=c99 -E macrotest.c
This yields:
(...)
literal
*literal
/literal
*pointer
**pointer
/ *pointer
Please note the extra space in the last line.
This looks like a feature to prevent macros from expanding to "/*" to me, which I'm sure is well-intentioned. But at a glance, I couldn't find anything pertaining to this behaviour in the C99 standard. Then again, I'm inexperienced at C. Can someone shed some light on this? Where is this specified? I would guess that a compiler adhering to C99 should not just insert extra spaces during macro expansion just because it would probably prevent programming mistakes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
源代码在被 CPP 处理之前已经被标记化。
因此,您拥有的是
/
和*
标记,它们不会隐式组合为/*
“标记”(因为 /* 是并不是真正的预处理器标记,我把它放在“”中)。如果使用 -E 输出预处理后的源 CPP 需要插入一个空格,以避免
/*
被后续编译器传递读取。相同的功能可以防止来自不同宏的两个例如
+
符号在输出时组合成++
标记。真正将两个预处理器标记粘贴在一起的唯一方法是使用 ## 运算符:
导致标记
foobar
导致标记
++
,但由于
无效>/*
不是有效的预处理器标记。The source code is already tokenized before being processed by CPP.
So what you have is a
/
and a*
token that will not be combined implicitly to a/*
"token" ( since /* is not really a preprocessor token I put it in "").If you use -E to output preprocessed source CPP needs to insert a space in order to avoid
/*
being read by a subsequent compiler pass.The same feature prevents from two e.g.
+
signs from different macros being combined into a++
token on output.The only way to really paste two preprocessor tokens together is with the ## operator:
results in the token
foobar
results in the token
++
, butis not valid since
/*
is not a valid preprocessor token.预处理器的行为是标准化的。在 http://en.wikipedia.org/wiki/C_preprocessor 的摘要中,您的结果正在观察的效果是:
“3:标记化 - 预处理器将结果分解为预处理标记和空格。它用空格替换注释”。
这发生在:
“4:宏扩展和指令处理”之前。
The behavior of the pre-processor is standardized. In the summary at http://en.wikipedia.org/wiki/C_preprocessor , the results you are observing are the effect of:
"3: Tokenization - The preprocessor breaks the result into preprocessing tokens and whitespace. It replaces comments with whitespace".
This takes place before:
"4: Macro Expansion and Directive Handling".