嵌套 FIRST_ARG 宏
Nested FIRST_ARG macro
我正在玩 C 宏,但我无法理解下面出现的问题。
#define FIRST_ARG(N, ...) N
#define FIRST_ARG_EXPANDED(N, ...) FIRST_ARG(N, __VA_ARGS__)
#define ELEMENTS(DEF, ...) DEF(1, 2, 3), \
DEF(4, 5, 6)
int main()
{
char array1[] = { FIRST_ARG(ELEMENTS(FIRST_ARG)) };
char array2[] = { FIRST_ARG_EXPANDED(ELEMENTS(FIRST_ARG)) };
printf("array1 size = %zu, array2 size = %zu \n", sizeof(array1), sizeof(array2));
return 0;
}
原来array1
和array2
不一样。 FIRST_ARG(ELEMENTS(FIRST_ARG))
扩展为 1, 4
而 FIRST_ARG_EXPANDED(ELEMENTS(FIRST_ARG))
结果为 1
。
我相信对此有一些解释。看Eclipse一步步展开:
谁能找到基于C标准的解释?
参数首先被宏替换,而不是重新扫描以用逗号分隔它们,因此变成 1, 4
的宏仍然是一个参数。但是,替换宏后,将重新扫描新序列,并以逗号分隔参数。
根据 C 2018 6.10.3.1 1,在替换宏本身之前处理宏的参数以进行宏替换:
… Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
因此,在 FIRST_ARG(ELEMENTS(FIRST_ARG))
中,我们首先替换 ELEMENTS(FIRST_ARG)
,从而生成 FIRST_ARG(1, 2, 3), FIRST_ARG(4, 5, 6)
。根据 6.10.3.4 1:
重新扫描此替换以进行进一步替换
… The resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.
重新扫描导致 FIRST_ARG(1, 2, 3), FIRST_ARG(4, 5, 6)
变为 1, 4
。因此,处理原始 FIRST_ARG
的参数的结果是 1, 4
。请注意,这本身就是整个第一个参数;它不会被重新处理,因此逗号会导致参数的分隔——它会作为 FIRST_ARG
的第一个参数的值。然后 FIRST_ARG
被参数的这个值替换,1, 4
.
在FIRST_ARG_EXPANDED(ELEMENTS(FIRST_ARG))
中,我们再次先替换参数,得到上面的参数1, 4
,然后我们有FIRST_ARG_EXPANDED(1, 4)
。这将替换为 FIRST_ARG(1, 4)
。现在已扫描,1, 4
的标记成为 FIRST_ARG
的单独参数,因此结果是第一个参数,1
.
综上所述,替换宏的一个参数产生一个参数。如果要重新扫描它以在逗号处分隔为多个参数,则必须使用另一个宏。
我正在玩 C 宏,但我无法理解下面出现的问题。
#define FIRST_ARG(N, ...) N
#define FIRST_ARG_EXPANDED(N, ...) FIRST_ARG(N, __VA_ARGS__)
#define ELEMENTS(DEF, ...) DEF(1, 2, 3), \
DEF(4, 5, 6)
int main()
{
char array1[] = { FIRST_ARG(ELEMENTS(FIRST_ARG)) };
char array2[] = { FIRST_ARG_EXPANDED(ELEMENTS(FIRST_ARG)) };
printf("array1 size = %zu, array2 size = %zu \n", sizeof(array1), sizeof(array2));
return 0;
}
原来array1
和array2
不一样。 FIRST_ARG(ELEMENTS(FIRST_ARG))
扩展为 1, 4
而 FIRST_ARG_EXPANDED(ELEMENTS(FIRST_ARG))
结果为 1
。
我相信对此有一些解释。看Eclipse一步步展开:
谁能找到基于C标准的解释?
参数首先被宏替换,而不是重新扫描以用逗号分隔它们,因此变成 1, 4
的宏仍然是一个参数。但是,替换宏后,将重新扫描新序列,并以逗号分隔参数。
根据 C 2018 6.10.3.1 1,在替换宏本身之前处理宏的参数以进行宏替换:
… Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
因此,在 FIRST_ARG(ELEMENTS(FIRST_ARG))
中,我们首先替换 ELEMENTS(FIRST_ARG)
,从而生成 FIRST_ARG(1, 2, 3), FIRST_ARG(4, 5, 6)
。根据 6.10.3.4 1:
… The resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.
重新扫描导致 FIRST_ARG(1, 2, 3), FIRST_ARG(4, 5, 6)
变为 1, 4
。因此,处理原始 FIRST_ARG
的参数的结果是 1, 4
。请注意,这本身就是整个第一个参数;它不会被重新处理,因此逗号会导致参数的分隔——它会作为 FIRST_ARG
的第一个参数的值。然后 FIRST_ARG
被参数的这个值替换,1, 4
.
在FIRST_ARG_EXPANDED(ELEMENTS(FIRST_ARG))
中,我们再次先替换参数,得到上面的参数1, 4
,然后我们有FIRST_ARG_EXPANDED(1, 4)
。这将替换为 FIRST_ARG(1, 4)
。现在已扫描,1, 4
的标记成为 FIRST_ARG
的单独参数,因此结果是第一个参数,1
.
综上所述,替换宏的一个参数产生一个参数。如果要重新扫描它以在逗号处分隔为多个参数,则必须使用另一个宏。