宏中的参数计数
Argument counting in macro
我正在尝试理解 C 预处理宏中的参数计数和 中的想法。我们有以下宏(为简单起见,我更改了参数的数量):
#define HAS_ARGS(...) HAS_ARGS_(__VA_ARGS__, 1, 1, 0,)
#define HAS_ARGS_(a, b, c, N, ...) N
据我了解,这个宏的目的是检查给定的可变参数是否为空。因此,在空的可变参数上,宏调用被替换为 0,这看起来不错。但是用一个参数它也会变成0,我觉得很奇怪。
HAS_ARGS(); //0
HAS_ARGS(123); //also 0
HAS_ARGS(1, 2); //1
我想我明白原因了。如果可变参数为空,a
将替换为空预处理标记,如果为单个参数,可变参数 a 将替换为产生相同结果的参数。
有没有办法在可变参数为空的情况下返回 0
,在不使用逗号吞入或其他非- 符合技巧。我是说
SOME_MACRO_F() //0
SOME_MACRO_F(234) //1
SOME_MACRO_F(123, 132) //1
//etc
您不能将零参数传递给 HAS_ARGS(...)
。 ISO C(和 C++,至少在接下来的两年)要求省略号对应于最后一个命名参数之后的至少一个附加参数。
如果没有命名的,那么宏至少需要传递一个参数。在 HAS_ARGS()
的情况下,额外的参数只是一个空的标记序列。零参数根本不可能。
这正是答案中的用例。目标宏需要至少一个参数。所以我们可以使用一个只接受 "overload resolution" 的省略号的包装器。更好的名字可能是 HAS_MORE_THAN_1_ARGS
。因为这就是谓词要告诉你的。 las,我赞成这个答案的简洁性。
在编译时似乎很难计算,但您可以在 运行 时通过将参数字符串化并测试字符串是否为空来完成。
测试 gcc
:
#include <stdio.h>
#define HAS_ARGS(...) (#__VA_ARGS__[0] != '[=10=]')
int main()
{
printf("%d %d %d %d\n",HAS_ARGS(),HAS_ARGS(10),HAS_ARGS(20,"foo"),HAS_ARGS(10,20));
return 0;
}
这会打印:
0 1 1 1
在幕后,这是预处理器输出的内容:
int main()
{
printf("%d %d %d %d\n",(("")[0] != '[=12=]'),(("10")[0] != '[=12=]'),(("20,\"foo\"")[
0] != '[=12=]'),(("10,20")[0] != '[=12=]'));
return 0;
}
我正在尝试理解 C 预处理宏中的参数计数和
#define HAS_ARGS(...) HAS_ARGS_(__VA_ARGS__, 1, 1, 0,)
#define HAS_ARGS_(a, b, c, N, ...) N
据我了解,这个宏的目的是检查给定的可变参数是否为空。因此,在空的可变参数上,宏调用被替换为 0,这看起来不错。但是用一个参数它也会变成0,我觉得很奇怪。
HAS_ARGS(); //0
HAS_ARGS(123); //also 0
HAS_ARGS(1, 2); //1
我想我明白原因了。如果可变参数为空,a
将替换为空预处理标记,如果为单个参数,可变参数 a 将替换为产生相同结果的参数。
有没有办法在可变参数为空的情况下返回 0
,在不使用逗号吞入或其他非- 符合技巧。我是说
SOME_MACRO_F() //0
SOME_MACRO_F(234) //1
SOME_MACRO_F(123, 132) //1
//etc
您不能将零参数传递给 HAS_ARGS(...)
。 ISO C(和 C++,至少在接下来的两年)要求省略号对应于最后一个命名参数之后的至少一个附加参数。
如果没有命名的,那么宏至少需要传递一个参数。在 HAS_ARGS()
的情况下,额外的参数只是一个空的标记序列。零参数根本不可能。
这正是答案中的用例。目标宏需要至少一个参数。所以我们可以使用一个只接受 "overload resolution" 的省略号的包装器。更好的名字可能是 HAS_MORE_THAN_1_ARGS
。因为这就是谓词要告诉你的。 las,我赞成这个答案的简洁性。
在编译时似乎很难计算,但您可以在 运行 时通过将参数字符串化并测试字符串是否为空来完成。
测试 gcc
:
#include <stdio.h>
#define HAS_ARGS(...) (#__VA_ARGS__[0] != '[=10=]')
int main()
{
printf("%d %d %d %d\n",HAS_ARGS(),HAS_ARGS(10),HAS_ARGS(20,"foo"),HAS_ARGS(10,20));
return 0;
}
这会打印:
0 1 1 1
在幕后,这是预处理器输出的内容:
int main()
{
printf("%d %d %d %d\n",(("")[0] != '[=12=]'),(("10")[0] != '[=12=]'),(("20,\"foo\"")[
0] != '[=12=]'),(("10,20")[0] != '[=12=]'));
return 0;
}