为什么宏扩展有时会添加一个 space?

Why does macro expansion add a space sometimes?

如果我这样做:

#define F a
F/

扩展为a/godbolt

如果我这样做:

#define F /
F/

它扩展为 / /,在 goodbolt

之间有一个 space

但是如果我将它转换成字符串并打印出来,它不会添加任何 spaces goodbolt:

#include <stdio.h>

#define STR_IMPL(x) #x
#define STR(x) STR_IMPL(x)

#define F /


int main() {
  puts(STR(F/));
}

为什么中间有一个 space,但只是在某些时候?在其他情况下是否允许添加更多的space?

宏在令牌级别工作。以字符串形式打印结果时添加空格以消除歧义。

F/ 是两个标记,F/。宏展开后,还是需要两个token,//。但是如果你把它们并排打印,它就会变成 //,这只是一个标记(注释)。所以中间需要有一个space。

长话短说:是的,宏扩展可以添加 spaces,因为 spaces 在宏操作的级别上无关紧要。

语言规范是这样的,高层次的:

  • 将输入分解为一系列标记。
  • 运行 该标记序列的预处理器(产生另一个标记序列)
  • 编译生成的标记序列。

步骤之间没有任何中间纯文本表示的规范。您在“预处理器输出”中看到的完全是供应商的心血来潮,只要整个翻译过程的最终结果符合规定即可。


#define F /STR(F/)的例子分析:

首先请注意 #define F / 后跟换行符意味着 F 被两个标记 w / 替换(我正在使用w 表示白色space 令牌)。

标记化后 STR(F/) 的预处理标记序列为:

  • STR(F/)

第一轮宏替换后的记号是:

  • w, STR_IMPL, (, w, /, /, )

第二轮结束后,令牌为:

  • w, "//" .

# 预处理运算符的定义包括删除前导白色space。所以 token 序列 w, /, / 变成 "//", 而不是 " //".

F/ 或两个斜杠之间从来没有任何 space。