(很奇怪?)GCC预处理器行为

时间:2011-01-27 21:38:17

标签: gcc c-preprocessor

我猜你们大多数使用过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 A B)无法执行,因为A将被B替换,最终结果应该相同。但如果不是,那么“A x”就无法发生!

我的问题:我错过了什么?显然我不知道预处理器如何工作的确切方式。你知道有关它的任何消息来源吗?

4 个答案:

答案 0 :(得分:13)

Self-Referential Macros解释道。扩展应用得很深,但一旦宏引用它就会停止。

答案 1 :(得分:5)

#define A B
#define B A C
#define C x

A -> B -> A C -> A x 
B -> A C -> B x

扩展是令牌“懒惰”的标记

答案 2 :(得分:5)

每个替换链最多可以访问任何宏定义一次。除此之外,这意味着您不能拥有递归宏。

第二个示例的替换将如下所示:

A --[evaluate A]--> B --[evaluate B]--> A C --[evaluate C]--> A x
B --[evaluate B]--> A C --[evaluate A,C]--> B x

在第一行的最后一步中,A未被评估,因为它之前已被调用过。同样,在第二行中,评估在B处停止,因为在第一步中已经访问过。

C99标准的相关部分将是 6.10.3.4重新扫描和进一步更换

答案 3 :(得分:3)

  好吧,好吧,也许不是任何人都愿意的   期待,但这是可以解释的。我猜   预处理器不知怎的想法   表示存在一些问题,并且   没有。

不。如果预处理器执行扩展,则它仅扩展符号一次。因此,在A的第一个示例中:A将扩展为B,B扩展为A,此处扩展停止。在第二行中,B扩展为A,扩展为B,扩展停止,因为我们已经扩展了B.

如果您将逻辑应用于第二个示例,那么结果将立即变得明显。