为什么宏扩展失败并且必须使用一个间接层?

时间:2016-04-30 22:50:51

标签: c macros c-preprocessor

当我使用宏参数计数器时,如果删除一个间接级别,我发现它无效。

原始代码:

#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);

我收到以下消息

  

错误:宏“COUNT_HELPER”需要7个参数,但只有4个

我的猜测是COUNT_DOWN()传递给COUNT_HELPER而不进行扩展。但我从Argument Prescan读到,宏参数在被替换为宏体之前已经完全展开。矛盾的行为让我感到困惑。

1 个答案:

答案 0 :(得分:2)

类功能宏的扩展在不连续的阶段运行:

  1. 参数从参数列表中标识出来。宏的参数列表中每个命名参数必须有一个参数,如果宏是可变参数,则至少还有一个参数。

  2. 每个参数都是完全宏扩展的。

  3. 宏调用替换为宏的替换文本,扩展的参数替换为相应的参数名称。

  4. 重新扫描扩展以进行其他宏扩展。

  5. (忽略了###运算符的影响,这些运算符在这里没有发挥作用。)

    我怀疑你的困惑是因为没有意识到步骤(2)与步骤(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()宏的全部目的。