【C语言笔记】【宏定义系列】 获取可变参数宏的参数数量

【C语言笔记】【linux宏定义系列】 获取可变参数宏的参数数量

linux宏定义系列内容。用于记录在linux之中各式各样的宏定义☺。

宏定义说明

用于获取可变参数宏实际传递了多少个参数。

例如调用COUNT_ARGS(1, 2, 3),我们填入了3个参数,返回值就是3;COUNT_ARGS(1),我们填入了1个参数,返回值就是1。

实现代码

#define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _n, X...) _n
#define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

宏定义中:

X...用于填入参数。

注意:该宏传入的参数不能超过12个。如果传入的参数大于12个,那么这个宏将返回第13个参数的参数值。

示例程序

int main(int argc, char* argv[])
{
 #define ARG2    arg2

    printf("%d\n", COUNT_ARGS());
    printf("%d\n", COUNT_ARGS(123));
    printf("%d\n", COUNT_ARGS(test, ARG2));
    printf("%d\n", COUNT_ARGS(123, test, ARG2));
    printf("%d\n", COUNT_ARGS(123, test, ARG2, "test"));
    printf("%d\n", COUNT_ARGS(123, test, ARG2, "test", 66));
    
    return 0;
}

运行后,结果为

0
1
2
3
4
5

结果与预期一致。

打开预编译的.i文件,看下宏的替换情况。

int main(int argc, char* argv[])
{
    printf("%d\n", 0);
    printf("%d\n", 1);
    printf("%d\n", 2);
    printf("%d\n", 3);
    printf("%d\n", 4);
    printf("%d\n", 5);

    return 0;
}

直接被替换成了对应传递进去的参数数量。

实现过程

  1. 我们先看__COUNT_ARGS的实现

    #define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _n, X...) _n
    

    这个宏要求至少传递14个参数,返回值就是这第14个参数。超过第14个的参数,会被X...给吸收走。

  2. 接下来再看下COUNT_ARGS的实现

    #define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    

    这个宏本身至少向__COUNT_ARGS传递了14个参数,满足了宏__COUNT_ARGS的需求。

    下面我们看下实际的使用情况。

    传参示例

    我们以上面示例程序中传递5个参数的情况进行举例:

    COUNT_ARGS(123, test, ARG2, "test", 66)
    

    展开后变为

    __COUNT_ARGS(,123, test, arg2, "test", 66, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    

    传递了19个参数给__COUNT_ARGS,接下来我们再与__COUNT_ARGS里的形参进行对应:

    _0,  _1,   _2,   _3,     _4, _5, _6, _7, _8, _9, _10, _11, _12, _n, X...
      , 123, test, arg2, "test", 66, 12, 11, 10,  9,   8,   7,   6,  5, 4, 3, 2, 1, 0
    

    可以看到_n的值等于5,宏返回的参数就是5,与传入的形参一致。

    没有参数的示例

    接下来我们看下没有传递参数的情况。

    当我们没有参数向COUNT_ARGS传递时,X的值为空,, ##X这部分会被删除。这里是使用了##的语法,当X为空字符串时,会连同最开始的被一并删除了。

    展开的效果如下:

    __COUNT_ARGS(, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    

    有14个参数传递给__COUNT_ARGS,然后传递的参数与__COUNT_ARGS里的形参进行一一对应:

    _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _n, X...
      , 12, 11, 10,  9,  8,  7,  6,  5,  4,   3,   2,   1,  0
    

    可以看到_n的值等于0,宏返回的参数就是0。

    从上述的示例可以看出,这个宏就是很巧妙的使用了可变参数宏的特性,将X...放在了参数列表的最前面,然后根据参数的数量,使_n的值等于对应参数数量的值。

    注意事项

    另外要注意传入的参数不能超过12个。如果传入的参数大于12个,那么这个宏将返回第13个参数的参数值。

    这里为什么会返回第13个参数的参数值呢?

    这里我们举个例子

    COUNT_ARGS(123, test, ARG2, "test", 66, 123, test, ARG2, "test", 66, "test", 66, 987, 999)
    

    展开后变为

    __COUNT_ARGS(,123, test, arg2, "test", 66, 123, test, arg2, "test", 66, "test", 66, 987, 999, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    

    接下来我们再与__COUNT_ARGS里的形参进行对应:

    _0,  _1,   _2,   _3,     _4,  _5,   _6,   _7,   _8,     _9, _10,    _11, _12,  _n, X...
      , 123, test, arg2, "test",  66,  123, test, arg2, "test",  66, "test",  66, 987, 999, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
    

    会发现,超过12个参数之后,不管参数的数量是多少,_n对应的永远是第13个参数的值。

[参考资料]

linux kernel 5.8

/include/linux/kernel.h


本文链接:https://blog.csdn.net/u012028275/article/details/118853297

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值