宏中的参数计数

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

LIVE DEMO

我想我明白原因了。如果可变参数为空,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;
}