首页 文章

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

提问于
浏览
5

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 使用来自 arity 扩展的字符 1 生成 . 那么 test_help_1 的扩张能再次召唤arity吗?我的gcc和clang版本都是这么认为的 .

任何人都可以争辩说gcc和clang所做的解释是标准中的某些要求吗?

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

1 回答

  • 2

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

    这些规则的想法是保证在这里不能保证无限递归 . 两次调用之间的宏评估有进展 .

相关问题