C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C语言 C++的默认参数

C语言实现C++的默认参数过程

作者:17岁boy想当攻城狮

还在羡慕C++的默认参数?本文教你用C语言宏巧妙模拟缺省参数功能,通过可变参数计数技巧,轻松实现函数参数默认值,核心利用__VA_ARGS__和宏推导,支持0到4个参数,代码来自实际项目,实用又简单

前言

在C++里,在声明一个函数时可以显示给参数指定默认参数值:

void add(int a, int b = 2)

这样你直接调用add(1)编译器在构建的时候会默认给第二个参数传递2,但是C语言没有这样的能力,C语言是一个面向底层的语言,它不具备那么多花里胡哨的特性,但是我们可以通过宏的方法来实现,C语言里宏给我们提供了极大的灵活性开发,特别是在Linux、Zephyr这样的操作系统里经常会使用到宏来包装实现API。

宏的可变参数计算方法

我记得很久之前我看到过Zephyr的一段源码,它为unit test提供的一套API,是经过宏包装的,主要功能是通过宏来指定数量来生成指定数量级的测试函数,

例如一个宏展3个Test函数,不需要自己去手写多个,其目的是为了测试一个API传递多个递阶数,所以这里先讲解一下如何利用宏来实现可变参数计算方法。

首先可以先看一段代码,这段代码是我最近为项目设计的日志模块所编写的,这里我简化了一下它的实现,目的是为了教学如何通过宏计算可变参数:

#define FAST_LOG_PRINT_NUMBER(_0, _1, _2, _3, _4, _n, ...) _n
#define FAST_LOG_MERG(...) FAST_LOG_PRINT_NUMBER(_, ##__VA_ARGS__,\ 
											 4, 3, 2, 1, 0)
#define FAST_LOG_CART_TRUE(a, b) a##b
#define FAST_LOG_CART(a, b) FAST_LOG_CART_TRUE(a, b)
#define FAST_LOG_PRINT(...) FAST_LOG_CART(FAST_LOG_PRINT_,\
        FAST_LOG_MERG(__VAR_ARGS__)) (__VAR_ARGS__)
#define FAST_LOG_PRINT_0() //0
#define FAST_LOG_PRINT_1(_1) //1
#define FAST_LOG_PRINT_2(_1, _2) //2
#define FAST_LOG_PRINT_3(_1, _2, _3) //3
#define FAST_LOG_PRINT_4(_1, _2, _3, _4) //4

这个宏计算最大支持4个参数传递同时也支持传递空参数,那么接下来来说一下这一段的实现原理,其核心函数就两个:

FAST_LOG_PRINT_NUMBER(_0, _1, _2, _3, _4, _n, ...) _n
FAST_LOG_MERG(...) FAST_LOG_PRINT_NUMBER(_, ##__VA_ARGS__,\ 
											 4, 3, 2, 1, 0)

FAST_LOG_MERG输入的是可变参数,然后将__VA_ARGS__传递给FAST_LOG_PRINT_NUMBER,这个函数是推导宏,推导出有几个参数然后决定使用哪个FAST_LOG_PRINT,这里推导的思路也非常简单,FAST_LOG_MERG最终只输出_n,而FAST_LOG_MERG在调用FAST_LOG_PRINT_NUMBER的时候,假如给的是FAST_LOG_PRINT_NUMBER(0, 1, 2),

那么最终宏翻译就是:

FAST_LOG_PRINT_NUMBER(_, 0, 1, 2, 4, 3, 2) 2

最终这里的_n就变成了2,这里其实就是利用一个巧妙的挤数字方法,因为FAST_LOG_PRINT_NUMBER里面__VA_ARGS__后面紧跟着顺序数字依次递减,当__VA_ARGS__参数越多,后面的数字递增到N的就越大,这样就能计算出到底有多少个参数了。

其中最前面的__,这个是为了解决0参数时候也就是调用宏不给参数时默认给一个0,让_n这个数字变为0。

那么通过这个实现我们就可以实现给默认缺省参数了,在FAST_LOG_PRINT_0、FAST_LOG_PRINT_1、FAST_LOG_PRINT_2调用不同函数时来依次传递不同参数,例如有一个set_sys_config的api,可以封装为:

FAST_LOG_PRINT_0() set_sys_config(a, b, c, d)
#define FAST_LOG_PRINT_1(_1) set_sys_config(_1, a, b, c)

在调用时只需要调用FAST_LOG_PRINT即可:

FAST_LOG_PRINT(); //无参数
FAST_LOG_PRINT(“hello world”); //1个参数

这样就实现类似c++的缺省参数,其实这个方法在Linux/zephyr里也有用过,不过不是用于缺省,缺省只是这种开发方法应用场景的其中一个,在内核里多数用于例如写test case,要写许多非常多的重复代码,那么这个时候就可以利用这种方法来动态生成不同参数级别的test case func。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文