宏中的参数计数

时间:2019-01-14 07:54:09

标签: c macros variadic-macros

我试图理解C预处理宏中的参数计数和this answer中的思想。我们有以下宏(为简单起见,我更改了参数数量):

#define HAS_ARGS(...) HAS_ARGS_(__VA_ARGS__, 1, 1, 0,)
#define HAS_ARGS_(a, b, c, N, ...) N

据我了解,此宏的目的是检查给定的varargs是否为空。因此,在空的varargs上,宏调用被替换为0,这似乎很好。但是只有一个参数,它也变成了0,我觉得很奇怪。

HAS_ARGS(); //0
HAS_ARGS(123); //also 0
HAS_ARGS(1, 2); //1

LIVE DEMO

我想我明白原因。如果空varargs a被替换为空的预处理令牌,则在单个参数vararg a的情况下被替换为产生相同结果的参数。

是否有一种方法可以在变量参数为空的情况下返回0,在参数编号为1到HAS_ARGS_宏调用中定义的情况下返回1,而无需使用逗号混淆或其他不符合要求的方法技巧。我的意思是

SOME_MACRO_F() //0
SOME_MACRO_F(234) //1
SOME_MACRO_F(123, 132) //1
//etc

2 个答案:

答案 0 :(得分:5)

您不能将零参数传递给HAS_ARGS(...)。 ISO C(和C ++,至少在接下来的两年中)要求,省略号至少与最后一个命名参数后的另一个自变量对应。

如果没有命名对象,则该宏至少需要传递一个参数。在HAS_ARGS()的情况下,额外的参数只是一个空的令牌序列。零参数根本不可能。

这正是答案中的用例。目标宏至少需要一个参数。因此,我们可以使用仅接受省略号的包装程序来实现“过载解析”。一个更好的名字可能是HAS_MORE_THAN_1_ARGS。因为这是谓词要告诉您的。 las,我希望简洁明了。

答案 1 :(得分:2)

似乎很难在编译时进行计算,但是您可以在运行时通过对参数进行字符串化并测试字符串是否为空来实现。

经过gcc的测试:

#include <stdio.h>
#define HAS_ARGS(...) (#__VA_ARGS__[0] != '\0')

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] != '\0'),(("10")[0] != '\0'),(("20,\"foo\"")[
0] != '\0'),(("10,20")[0] != '\0'));
    return 0;
}