【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

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
### 回答1: 在C语言中,程序员可以定义不同类型的函数,这些函数可以接受不同类型的参数。在函数定义中,程序员可以使用参数列表来声明函数接受哪些参数参数列表指定参数的类型、顺序和名称。 在调用函数时,程序员必须向函数传递与其参数类型匹配的值。如果传递的值与参数类型不匹配,编译器将会发出警告或错误。 使用函数参数可以让程序员编写更通用、可重用的代码。例如,如果程序员需要编写一个函数来计算两个整数的和,可以定义一个接受两个int类型参数的函数。如果程序员需要计算两个浮点数的和,可以定义一个接受两个float类型参数的函数。 程序员也可以使用指针作为函数参数。指针是一个变量,它存储了另一个变量的地址。通过传递指向变量的指针作为函数参数,函数可以修改该变量的值。 因此,通过选择不同类型的参数,程序员可以根据需要定义不同的函数。这样可以使函数更通用、更灵活,并且可以减少代码的冗余。 ### 回答2: 在C语言中,可以使用宏定义来根据参数选择不同的宏定义。可以通过宏定义中的条件判断语句来实现这一功能。 首先,在宏定义中使用条件判断语句,可以使用预处理指令#ifdef和#endif来选择性地定义某个宏定义。例如: #define PARAMETER 1 #ifdef PARAMETER // 定义参数为1时的宏定义 #define MACRO_DEFINITION_1 #else // 定义参数为其他值时的宏定义 #define MACRO_DEFINITION_2 #endif 在上述代码中,如果参数PARAMETER的值为1,则会定义MACRO_DEFINITION_1宏定义;如果参数PARAMETER的值为其他值,则会定义MACRO_DEFINITION_2宏定义。 其次,要根据参数选择不同的宏定义,可以利用函数式的特性,使用参数值来进行选择。例如: #define SELECT_MACRO_DEFINITION(PARAMETER) \ (PARAMETER == 0 ? MACRO_DEFINITION_1 : MACRO_DEFINITION_2) 在上述代码中,通过函数式SELECT_MACRO_DEFINITION来根据参数PARAMETER的值选择不同的宏定义。如果参数PARAMETER的值为0,则选择MACRO_DEFINITION_1宏定义;如果参数PARAMETER的值为其他值,则选择MACRO_DEFINITION_2宏定义。 综上所述,通过使用条件判断语句和函数式,可以根据参数选择不同的宏定义。这种方法可以在编译时根据参数的不同选择实现不同的宏定义,避免了运行时的性能开销。 ### 回答3: 在C语言中,可以通过使用宏定义来根据参数选择不同的宏定义。借助预处理指令和的特性,我们可以在编译阶段根据参数的不同选择不同的宏定义。 首先,可以使用条件编译指令`#ifdef`和`#endif`来实现根据参数的选择。假设有两个宏定义`#define OPTION_A`和`#define OPTION_B`,我们可以通过如下宏定义实现根据参数选择不同的宏定义: ``` #define OPTION_A // 或者 // #define OPTION_B ``` 之后,在代码的其他部分,可以使用条件编译指令`#ifdef`和`#endif`来根据参数的选择执行相应的代码。例如: ``` #ifdef OPTION_A // 在此处编写针对OPTION_A的代码 // 例如 printf("使用了OPTION_A宏定义\n"); #endif #ifdef OPTION_B // 在此处编写针对OPTION_B的代码 // 例如 printf("使用了OPTION_B宏定义\n"); #endif ``` 当参数中定义了`OPTION_A`时,编译器将会编译对应的代码段,并执行其中的代码。而当参数中定义了`OPTION_B`时,编译器将会编译对应的代码段,并执行其中的代码。 需要注意的是,根据参数选择不同的宏定义时,只有定义了才会编译对应代码段,因此未定义的对应的代码段将会被忽略。 通过使用宏定义来根据参数选择不同的宏定义,可以在编译阶段根据需要灵活地选择不同的代码实现。这在代码的复用和优化方面具有很大的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值