预处理运算符“##”

Preprocessing operator "##"

在学习 'Preprocessor Operators' 时,我在一本书中找到了一个定义:

#define CONCAT(x,y) x##y

调用 CONCAT(a,b) 给出了所需的输出 ab。但是 CONCAT(a,CONCAT(b,c)) 不会给出 abc 而是给出奇数输出。

Book 解释说 替换列表中 ## 之前或之后的宏参数在替换时不会扩展。 所以 CONCAT(a,CONCAT(b,c)) 扩展为无法进一步扩展的 aCONACT(b,c),因为没有名为 aCONCAT 的宏。 好的,我明白了,但书中进一步提到,这个问题可以通过定义一个只调用第一个宏的第二个宏来解决。范例

#define CONCAT2(x,y) CONCAT(x,y)

现在写入 CONCAT2(a,CONCAT2(b,c)) 会产生所需的列表 abc

但是怎么办?我认为 CONCAT2(a,CONCAT2 (b,c)) 将被 CONCAT(a,CONCAT2(b,c)) 取代,后者进一步扩展为 aCONCAT2(b,c)。现在没有像第一种情况那样名为 aCONCAT2 的宏,那么所需的输出是怎么来的?

这就是CONCAT2(a,CONCAT2 (b,c))工作正常的证明。

看到编译器不会显示任何错误。除了使用 getch( ) 函数的警告。

如果你有

#define CONCAT(x,y)   x##y
#define CONCAT2(x,y)  CONCAT(x,y)

然后当预处理器看到

CONCAT(a,CONCAT(b,c))

它知道 CONCAT(x,y) 的替换列表是 x##y,所以它将用 a[=85= 替换 x ] 和 yCONCAT(b,c)。唯一的问题是,它会在替换之前扩展 a and/or CONCAT(b,c) 吗? a 不是宏,因此无法展开,在替换列表 x##y 中,y 前面有 ##,因此不会对参数 CONCAT(b,c ).所以替换是在没有扩展的情况下完成的,替换列表变成了##CONCAT(b,c),然后在检查更多宏之前,它处理了##并且替换列表变成了aCONCAT(b,c)。

如果预处理器看到

CONCAT2(a,CONCAT2(b,c))

它知道 CONCAT2(x,y) 的替换列表是 CONCAT(x,y),所以它将用 a[ 替换 x =85=] 和 yCONCAT2(b,c)。唯一的问题是,它会在替换之前扩展 a and/or CONCAT2(b,c) 吗? a 不是宏,因此无法展开,在替换列表 CONCAT(x,y) 中,y 前面没有#或##,或后跟##,因此 CONCAT2(b,c) 在替换之前完全展开。所以CONCAT2(b,c)展开为CONCAT(b,c),又展开为b##c,不可能再展开,所以y 替换为 b##c。替换列表 x##y 变为 a##b##c,然后变为 ab##c,然后变为 abc,或者变为 a##bc,然后变为 abc。

如果预处理器看到

CONCAT2(a,CONCAT(b,c))

它知道 CONCAT2(x,y) 的替换列表是 CONCAT(x,y),所以它将用 a[ 替换 x =85=] 和 yCONCAT(b,c)。唯一的问题是,它会在替换之前扩展 a and/or CONCAT(b,c) 吗? a 不是宏,因此无法展开,在替换列表 CONCAT(x,y) 中,y 前面没有#或##,或后跟##,因此 CONCAT(b,c) 在替换之前完全展开。所以CONCAT(b,c)被展开为b##c,无法进一步展开,所以将y替换为b##c,替换列表 x##y 变为 a##b##c,或者变为 ab##c 然后变为 abc,或者变为 a##bc 然后变为 abc。

如果预处理器看到

CONCAT(a,CONCAT2(b,c))

它知道 CONCAT(x,y) 的替换列表是 x##y,所以它将用 a[=85= 替换 x ] 和 yCONCAT2(b,c)。唯一的问题是,它会在替换之前扩展 a and/or CONCAT2(b,c) 吗? a 不是宏,因此无法展开,在替换列表 x##y 中,y 前面有 ##,因此不会对参数 CONCAT2(b,c ).所以替换是在没有扩展的情况下完成的,替换列表变成了##CONCAT2(b,c),然后在检查更多宏之前它处理了##并且替换列表变成了aCONCAT2(b,c).

你可能会想

#define CONCAT2(x,y)  CONCAT(x,y)

表示

CONCAT2(x,y) 应与 CONCAT(x, y)

相同

但请记住:

  1. CONCAT(x,y) 的替换列表是 x##y,因为当预处理器看到 CONCAT 的实例时,x 后面跟着## y 前面跟着##宏,它不会在替换前扩展对应于 x 或 y 的参数。但是 CONCAT2(x,y) 的替换列表是 CONCAT(x,y) 并且替换中的 x 和 y 前面都没有 # 或 ## 或后面有 ##,因此当预处理器看到 CONCAT2 宏的实例时,它将在替换之前完全扩展参数中的任何宏。

  2. 参数的宏扩展(如果允许)发生在替换之前。因此在 CONCAT2(a,CONCAT(b,c)) 中,CONCAT(b,c) 参数在替换之前被扩展。所以我们得到 CONCAT2(a, b##c) 而不是 CONCAT(a, CONCAT(b,c)).