use*_*069 1 c-preprocessor preprocessor-directive
如果我有:
#define X 5
#define Y X
Run Code Online (Sandbox Code Playgroud)
这种事情的预处理器会发生什么?它是否遍历整个文件并将每个 X 更改为 5,然后返回到下一个定义,然后将每个 Y 更改为 5(因为在前一次迭代中 Y 得到了 5)?
C 标准对于宏的扩展方式有一个特殊的术语。
实际上,宏名称存储在“此时定义的所有宏”的大表中。左侧的每个表条目“宏名称”(以及中间的任何参数)和右侧的“扩展令牌流”。
当要扩展宏时(因为它出现在某个非预处理器行中,或位于必须扩展的预处理器行中的某个位置——例如,您可以#define STDIO <stdio.h>然后#include STDIO),表条目被“涂成蓝色” ,然后读取替换令牌流(使用标准也规定的参数扩展)。
如果替换令牌流包含原始宏名称,则不再匹配,因为“蓝色油漆”覆盖了名称。
当替换令牌流被完全处理后,“蓝色油漆”被移除,重新暴露名称。
因此:
#define X 5
Run Code Online (Sandbox Code Playgroud)
将X:(无参数)添加5到表中。
然后:
#define Y X
Run Code Online (Sandbox Code Playgroud)
添加:Y:(无参数),X到表中。
在文件后面的某个地方,您可能会出现 token Y。假设以上都没有被#undef编辑(从表中删除),编译器必须首先“将表条目绘制为Y蓝色”并将标记替换Y为标记X。
接下来,编译器必须“将表条目绘制为X蓝色”,并用 token 替换Xtoken 5。
令牌5不是预处理器宏名称(根据定义它不能是),因此令牌5超出了预处理阶段的范围。现在,“蓝色油漆”从X表条目中删除,就像这样;然后从Y条目中删除“蓝色油漆” ,这也完成了。
如果你改写:
#define Y Y, Y, Y, the letter is called Y!
Run Code Online (Sandbox Code Playgroud)
那么在遇到后面的 token 时Y,序列将是:
Y蓝色的油漆条目Y , Y , Y , the letter is called Y !Y那些不匹配和,不能匹配的标记被涂成蓝色,所以这些都被传递给编译器的其余部分;the, letter, is, 和called必须检查但可能不在表中,因此传递; Y仍然涂成蓝色所以不匹配并传递,!不能匹配并传递。