为什么宏展开失败而必须使用一层间接寻址?
Why the macro expansion fails and one level of indirection must be used?
当我在玩宏参数计数器时,我发现如果删除一级间接它就无法工作了。
原代码:
#define COUNT_ARGS(...) \
COUNT_INDIR(__VA_ARGS__,COUNT_DOWN())
#define COUNT_INDIR(...) \
COUNT_HELPER(__VA_ARGS__)
#define COUNT_HELPER( \
_1, _2, _3, _4, _5, N,...) N
#define COUNT_DOWN() \
5, 4, 3, 2, 1, 0
COUNT_ARGS(1,2,3);
我编辑的版本:
#define COUNT_ARGS(...) \
COUNT_HELPER(__VA_ARGS__,COUNT_DOWN())
#define COUNT_HELPER( \
_1, _2, _3, _4, _5, N,...) N
#define COUNT_DOWN() \
5, 4, 3, 2, 1, 0
COUNT_ARGS(1,2,3);
我收到了以下消息
error: macro "COUNT_HELPER" requires 7 arguments, but only 4 given
我的猜测是 COUNT_DOWN() 被传递给 COUNT_HELPER 而没有被展开。但是我从 Argument Prescan 中读到,宏参数在被替换为宏体之前已经完全展开了。自相矛盾的行为让我很困惑。
类函数宏的扩展在离散阶段运行:
参数是从参数列表中识别出来的。宏的参数列表中的每个命名参数必须有一个参数,如果宏是可变的,则至少还有一个参数。
每个参数都是完全宏展开的。
宏调用被宏的替换文本替换,扩展参数替换相应的参数名称。
重新扫描扩展以进行额外的宏扩展。
(这忽略了 #
和 ##
运算符的影响,它们在这里没有发挥作用。)
我怀疑您的困惑是由于没有意识到步骤 (2) 与步骤 (1) 完全分开并在步骤 (1) 之后发生的。一旦确定了宏参数,就设置了它们的编号以及它们与宏参数的对应关系。扩展它们不会修改它,无论扩展文本的性质如何。或者,您可能不理解宏替换文本中的宏调用不会在宏定义本身中展开,而是在展开宏过程的第 (4) 步展开。
因此,给定这些(原始)定义...
#define COUNT_ARGS(...) \
COUNT_INDIR(__VA_ARGS__,COUNT_DOWN())
#define COUNT_INDIR(...) \
COUNT_HELPER(__VA_ARGS__)
#define COUNT_HELPER( \
_1, _2, _3, _4, _5, N,...) N
#define COUNT_DOWN() \
5, 4, 3, 2, 1, 0
...这是展开的顺序:
COUNT_ARGS(1,2,3);
COUNT_INDIR(1,2,3,COUNT_DOWN());
COUNT_HELPER(1,2,3,5,4,3,2,1,0);
3;
另一方面,根据您修改后的定义...
#define COUNT_ARGS(...) \
COUNT_HELPER(__VA_ARGS__,COUNT_DOWN())
#define COUNT_HELPER( \
_1, _2, _3, _4, _5, N,...) N
#define COUNT_DOWN() \
5, 4, 3, 2, 1, 0
...扩展是这样的:
COUNT_ARGS(1,2,3);
COUNT_HELPER(1,2,3,COUNT_DOWN());
错误
正如错误消息告诉您的那样,提供给 COUNT_HELPER()
的参数太少。 COUNT_HELPER()
的扩展会产生一个逗号分隔的列表在这一点上是无关紧要的。
使 COUNT_DOWN()
扩展为 COUNT_HELPER()
的多个参数是原始 COUNT_INDIR()
宏的全部目的。
当我在玩宏参数计数器时,我发现如果删除一级间接它就无法工作了。
原代码:
#define COUNT_ARGS(...) \
COUNT_INDIR(__VA_ARGS__,COUNT_DOWN())
#define COUNT_INDIR(...) \
COUNT_HELPER(__VA_ARGS__)
#define COUNT_HELPER( \
_1, _2, _3, _4, _5, N,...) N
#define COUNT_DOWN() \
5, 4, 3, 2, 1, 0
COUNT_ARGS(1,2,3);
我编辑的版本:
#define COUNT_ARGS(...) \
COUNT_HELPER(__VA_ARGS__,COUNT_DOWN())
#define COUNT_HELPER( \
_1, _2, _3, _4, _5, N,...) N
#define COUNT_DOWN() \
5, 4, 3, 2, 1, 0
COUNT_ARGS(1,2,3);
我收到了以下消息
error: macro "COUNT_HELPER" requires 7 arguments, but only 4 given
我的猜测是 COUNT_DOWN() 被传递给 COUNT_HELPER 而没有被展开。但是我从 Argument Prescan 中读到,宏参数在被替换为宏体之前已经完全展开了。自相矛盾的行为让我很困惑。
类函数宏的扩展在离散阶段运行:
参数是从参数列表中识别出来的。宏的参数列表中的每个命名参数必须有一个参数,如果宏是可变的,则至少还有一个参数。
每个参数都是完全宏展开的。
宏调用被宏的替换文本替换,扩展参数替换相应的参数名称。
重新扫描扩展以进行额外的宏扩展。
(这忽略了 #
和 ##
运算符的影响,它们在这里没有发挥作用。)
我怀疑您的困惑是由于没有意识到步骤 (2) 与步骤 (1) 完全分开并在步骤 (1) 之后发生的。一旦确定了宏参数,就设置了它们的编号以及它们与宏参数的对应关系。扩展它们不会修改它,无论扩展文本的性质如何。或者,您可能不理解宏替换文本中的宏调用不会在宏定义本身中展开,而是在展开宏过程的第 (4) 步展开。
因此,给定这些(原始)定义...
#define COUNT_ARGS(...) \
COUNT_INDIR(__VA_ARGS__,COUNT_DOWN())
#define COUNT_INDIR(...) \
COUNT_HELPER(__VA_ARGS__)
#define COUNT_HELPER( \
_1, _2, _3, _4, _5, N,...) N
#define COUNT_DOWN() \
5, 4, 3, 2, 1, 0
...这是展开的顺序:
COUNT_ARGS(1,2,3);
COUNT_INDIR(1,2,3,COUNT_DOWN());
COUNT_HELPER(1,2,3,5,4,3,2,1,0);
3;
另一方面,根据您修改后的定义...
#define COUNT_ARGS(...) \
COUNT_HELPER(__VA_ARGS__,COUNT_DOWN())
#define COUNT_HELPER( \
_1, _2, _3, _4, _5, N,...) N
#define COUNT_DOWN() \
5, 4, 3, 2, 1, 0
...扩展是这样的:
COUNT_ARGS(1,2,3);
COUNT_HELPER(1,2,3,COUNT_DOWN());
错误
正如错误消息告诉您的那样,提供给 COUNT_HELPER()
的参数太少。 COUNT_HELPER()
的扩展会产生一个逗号分隔的列表在这一点上是无关紧要的。
使 COUNT_DOWN()
扩展为 COUNT_HELPER()
的多个参数是原始 COUNT_INDIR()
宏的全部目的。