是通过令牌连接未指定的行为重复宏调用吗?

时间:2016-07-25 20:06:32

标签: c macros c-preprocessor c11

C11标准承认关于宏扩展中可能出现的至少一种情况的模糊性,当像宏这样的函数扩展到其未被激活的名称时,并且由下一个预处理令牌调用。标准中给出的例子是这样的。

#define f(a) a*g
#define g(a) f(a)

// may produce either 2*f(9) or 2*9*g
f(2)(9)

该示例没有说明当扩展宏M时会发生什么,并且结果的全部或部分通过令牌连接贡献给第二个预处理令牌M,后者被调用。

问题:此类调用是否被阻止?

以下是此类调用的示例。这个问题往往只在使用一组相当复杂的宏时出现,所以这个例子是为了简单起见而设计的。

// arity gives the arity of its args as a decimal integer (good up to 4 args)
#define arity(...) arity_help(__VA_ARGS__,4,3,2,1,)
#define arity_help(_1,_2,_3,_4,_5,...) _5

// define 'test' to mimic 'arity' by calling it twice
#define test(...) test_help_A( arity(__VA_ARGS__) )
#define test_help_A(k) test_help_B(k)
#define test_help_B(k) test_help_##k
#define test_help_1 arity(1)
#define test_help_2 arity(1,2)
#define test_help_3 arity(1,2,3)
#define test_help_4 arity(1,2,3,4)

// does this expand to '1' or 'arity(1)'?
test(X)

test(X)扩展为test_help_A( arity(X) ),在重新扫描时调用test_help_A,在替换前扩展其arg,因此与test_help_A(1)相同,后者生成test_help_B(1) },产生test_help_1。这很清楚。

所以,问题就在这里。 test_help_1是使用来自1扩展的字符arity生成的。那么test_help_1的扩张能否再次召唤arity?我的gcc和clang版本都是这么认为的。

有人可以说gcc和clang所做的解释是标准内容所要求的吗?

是否有人意识到以不同方式解释这种情况的实现?

1 个答案:

答案 0 :(得分:2)

我认为gcc和clang的解释是正确的。 arity的两个扩展不在同一个调用路径中。第一个来自test_help_A论证的扩展,第二个来自test_help_A本身的扩张。

这些规则的思想是保证在这里无法保证无限递归。两次调用之间的宏评估取得了进展。