(奇怪?)GCC 预处理器行为
我想大多数使用过 C/C++ 的人都对预处理器的工作原理有一定的直觉(或多或少)。直到今天我也是这么认为的,但事实证明我的直觉是错误的。故事是这样的:
今天我尝试了一些东西,但我无法解释结果。 首先考虑下面的代码:
#define A B
#define B A
A
B
会发生什么?好吧,使用 -E 标志编译后的结果是这样的:
A
B
好吧,也许不是任何人所期望的,但它是可以解释的。我猜想预处理器以某种方式发现存在一些问题,但什么也没做。
我尝试的下一件事是:
#define A B
#define B A C
#define C x
A
B
现在对我来说,无法解释的结果:
A x
B x
这是怎么发生的?我无法弄清楚这是如何发生的任何合理的方式。第一条命令(#define AB)无法执行,因为这样 A 就会被 B 替换,并且两者的最终结果应该相同。但如果不是的话,那么“A x”就不可能发生!
我的问题:我错过了什么?显然我不知道预处理器的确切工作方式。你知道有关它的任何消息来源吗?
I guess most of you who have worked with C/C++ have an intuition of how the preprocessor works (more or less). I thought so until today, but my intuition was proved wrong. Here is the story:
Today I tried something, but I can not explain the result.
First consider the following code:
#define A B
#define B A
A
B
What happens? Well, the result after compiling it with the -E flag is this:
A
B
Well, ok, maybe not what anyone would expect, but it is explainable. I guess that the preprocessor somehow figured out that there is some problem, and did nothng.
The next thing I tried was this:
#define A B
#define B A C
#define C x
A
B
Now to the, for me, unexplainable result:
A x
B x
How did this happen? I can not figure out any reasonable way of how this happened. The first command (#define A B) can not be executed, because then A would be replaced by B, and the final result should be same for both. But if it is not, then there is no way that "A x" can happen!
My question: What am I missing? Obviously I don't know the exact way of how the preprocessor works. Do you know any sources about it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
自引用宏解释。扩展被深入应用,但一旦宏引用自身就会停止。
Self-Referential Macros explains. Expansion is applied deeply but stops once a macro references itself.
扩展是“惰性地”逐个令牌进行的
Expansion is token by token "lazily"
每个替换链最多可以访问任何宏定义一次。除此之外,这意味着您不能使用递归宏。
第二个示例的替换将如下所示:
在第一行的最后一步中,不会评估
A
,因为它之前已被调用。同样,在第二行中,计算在B
处停止,因为它已在第一步中被访问过。C99 标准的相关部分是6.10.3.4 重新扫描和进一步替换。
Each chain of substitutions can visit any macro definition at most once. Among other things, this means that you can't have recursive macros.
The substitutions for your second example will look like this:
During the last step of the first line,
A
is not evaluated because it was already invoked previously. Similarly, in the second line, evaluation stops atB
because it has already been visited during the first step.The relevant section of the C99 standard would be 6.10.3.4 Rescanning and further replacement.
没有。如果预处理器进行扩展,则它仅扩展符号一次。因此,在 A 的第一个示例中:A 扩展为 B,B 扩展为 A,此处扩展停止。在第二行中,B 扩展为 A,A 扩展为 B,此处扩展停止,因为我们已经扩展了 B。
如果您将逻辑应用于第二个示例,那么结果将立即变得显而易见。
Nope. If the preprocessor does an expansion, it expands a symbol only once. So in your first example for the A: A gets's expanded to B, B expands to A and here the expansion stops. In the second line the B gets expanded to an A which expands to a B, where expansion stops, because we expanded B already.
If you apply logic to your second example, then the result becomes immediately obvious.