__VA_ARGS__ 的嵌套宏不会展开

nested macro with __VA_ARGS__ does not expand

为了获得 __VA__ARGS__ 的数量,我阅读了 this answer 并且它有效。但是我觉得PP_NARG_是多余的,我看不出PP_RSEQ_N为什么是宏函数。所以我修改代码如下

#include <assert.h>
#define PP_RSEQ_N \
         63,62,61,60,                   \
         59,58,57,56,55,54,53,52,51,50, \
         49,48,47,46,45,44,43,42,41,40, \
         39,38,37,36,35,34,33,32,31,30, \
         29,28,27,26,25,24,23,22,21,20, \
         19,18,17,16,15,14,13,12,11,10, \
         9,8,7,6,5,4,3,2,1,0
#define PP_NARG(...) \
         PP_ARG_N(__VA_ARGS__,PP_RSEQ_N)
#define PP_ARG_N( \
          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
         _61,_62,_63,N,...) N

/* Some test cases */

int main() {
  assert(PP_NARG(1,2,"yes",!)==4);
}

我收到错误和注释。

main.c:24:33: error: macro "PP_ARG_N" requires 65 arguments, but only 5 given
   assert(PP_NARG(1,2,"yes",!)==4);
                                 ^

好像在PP_NARG里,PP_RSEQ_N没有展开。但为什么?我知道用###宏是不会展开的,但事实并非如此

另外我想知道为什么 this answer 中需要 PP_NARG_ ,为什么 PP_RSEQ_N 是一个宏函数,而不是普通的宏(无参数)?

宏调用的本质是宏参数不在宏调用中展开。标准中的 §6.10.3.1.

规定了准确的程序
  1. After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place.

所以宏的参数由当时令牌流中实际存在的逗号分隔,无论替换的参数可能是什么样子。

收集参数后,宏主体中宏参数的使用将替换为参数。在大多数情况下,此时会扩展参数,但是(正如您所注意到的)如果参数用作 ### 表达式的一部分,则参数不会被宏替换 用于该用途。此外,在宏体中根本不需要使用参数,因此在这种情况下根本不需要扩展参数。

一旦宏参数被相应的参数替换并且 ### 运算符被求值,生成的令牌流将通过宏处理器传回。在此重新扫描期间,将扩展宏主体中使用的任何宏。

现在,PP_NARG 的作者实际上想构造一个宏调用,其中包含 PP_NARG 的原始可变参数参数,然后是 PP_RSEQ_N 的扩展。由于宏参数 PP_RSEQ_N 的展开直到出现它的宏调用的展开才会发生,因此有必要引入额外的宏展开级别; PP_NARG_ 宏用于构造对 PP_NARG 的调用。 (你可以通过根本不使用 PP_RSEQ_N 来避免这种情况,而是将倒计时直接放在对 PP_NARG 的调用中。但是有很多理由可以避免这种解决方案;添加额外的宏级别更清晰替换。)

将像 PP_RSEQ_N 这样的宏定义为不带参数的类似函数的宏而不是简单的宏的通常原因是能够在不展开宏的情况下传递宏的名称。在此代码段中似​​乎并非如此,但它可能存在于提取该代码段的代码中的其他地方。