代码之家  ›  专栏  ›  技术社区  ›  Some Name

宏中的参数计数

  •  2
  • Some Name  · 技术社区  · 7 年前

    我试图理解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 如果varargs为空,则返回1;如果参数号从1到中定义的 HAS_ARGS_ 不使用逗号吞咽或其他不一致技巧的宏调用。我的意思是

    SOME_MACRO_F() //0
    SOME_MACRO_F(234) //1
    SOME_MACRO_F(123, 132) //1
    //etc
    
    2 回复  |  直到 7 年前
        1
  •  5
  •   StoryTeller - Unslander Monica    7 年前

    不能将零参数传递给 HAS_ARGS(...) . ISOC(和C++,至少在接下来的两年中)要求省略号对应于最后一个命名后的至少一个附加参数。

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

    这正是答案中的用例。目标宏至少需要一个参数。所以我们可以使用一个只接受省略号的包装器来进行“重载解析”。一个更好的名字可能是 HAS_MORE_THAN_1_ARGS . 因为这就是谓词要告诉你的。唉,我赞成简洁的回答。

        2
  •  2
  •   Jean-François Fabre    7 年前

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

    用试验 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;
    }
    
    推荐文章