以下内容为自己的学习笔记,如需求转载,请声明原文链接 微信大众号「ENG八戒」mp.weixin.qq.com/s/nj0C9SbAu…
自从上一篇关于 C 言语单个参数函数的默认值完成《C言语函数也能够给形参添加默认值?》发表以来,有很多的同学反应想知道多参数函数的默认值又该怎样完成,今天特别整理相关代码和完成思路阐明如下。
因为 C 言语本身是不提供函数默认值功用和相关语法的,为了完成函数参数的默认值,归根到底是对原有函数参数的主动填充,填充的值就是默认值。
那么怎样填充参数值,又不会影响程序性能呢?能够运用宏界说的灵活性在代码的编译预处理期做一些替换操作,本文和《C言语函数也能够给形参添加默认值?》文章的基本思路类似,但是完成上会繁琐一些,终究的方针是完成从单参数默认值向多参数默认值迭代晋级。
设想一下总体思路:
因为带有默认值的函数在运用时,形式上输入的参数个数是不定的,所以需求核算函数实践输入参数的个数,然后针对未输入的参数填充默认值。所以这儿提出两个问题,一个是怎样核算函数实践输入参数的个数,另一个是怎样对参数填充默认值?
接下来将对提出来的问题逐一破解。
核算函数实践输入参数的个数
咱们先来界说一个带有 2 个输入参数的方针函数 _fun2():
void _fun2(int val1, int val2)
{
printf("fun inputs val1:%d, val2:%dn", val1, val2);
}
参阅《C言语函数也能够给形参添加默认值?》文章的基本思路,界说一个变长参数宏 fun2() 代表方针函数 _fun2(),原来调用方针函数 _fun2() 的语句将变成直接调用宏 fun2(),而方针函数 _fun2() 间接被调用。
但是因为咱们的思路里多了一个因素—函数实践输入参数的个数,所以变长参数宏 fun2() 和方针函数 _fun2() 之间还需求多一层转化,下面统称为转化函数 _funs(),函数实践输入参数(调用宏 fun2() 时输入的参数)的个数作为参数输入到转化函数 _funs(),方针函数 _fun2() 在转化函数 _funs() 内部被调用。
#define fun2(...) _funs(ARGC(__VA_ARGS__), 123, 456, ##__VA_ARGS__)
void _funs(int real_param_num, ...)
{
...
// _fun2(val1, val2);
}
宏界说 ARGC() 用于核算函数实践输入参数的个数,123 和 456 作为方针函数 _fun2() 的参数默认值。real_param_num 是转化函数 _funs() 的第一个参数,用于接纳变长参数宏 fun2() 被调用时输入的参数个数。
另外,鉴于视乎实践需求,方针函数的参数也能够是 2 之外的其它数目,所以为了便于扩展转化函数 _funs() 的应用范围,需求输入方针函数的完整参数个数,持续迭代转化函数 _funs()。
#define fun2(...) _funs(2, ARGC(__VA_ARGS__), 123, 456, ##__VA_ARGS__)
void _funs(int param_num_max, int real_param_num, ...)
{
...
// _fun2(val1, val2);
}
用变长参数宏 fun2() 代表有 2 个输入参数的方针函数 _fun2(),param_num_max 指定方针函数的完整参数个数。
ARGC 怎样完成?
为什么运用宏界说来核算函数实践输入参数的个数?
因为 C 运转进程中确认参数个数会耗费系统资源,并下降程序运转功率,所以尽量采用在编译预处理时核算的宏界说。
暂定参数个数上限是 2 个,用宏界说预处理对参数的打开来统计参数个数,涉及占位符的妙用(信任会令你开眼界):
#define __ARGS(X) (X)
#define __ARGC_N(_0,_1,N,...) N
#define __ARGC(...) __ARGS(__ARGC_N(__VA_ARGS__,2,1))
#define ARGC(...) __ARGC(__VA_ARGS__)
其中 _0, _1,… 是预处理占位符,用于在宏界说打开参数时逐个匹配参数,_0 匹配第一个参数,_1 匹配第二个参数,以此类推,终究 N 用于匹配 __ARGC_N(__VA_ARGS__,2,1)
后边的逆序数字 2 或许 1,这个 N 就是终究核算所得的参数个数。
测验一下对参数个数的核算效果:
printf("ARGC() arg num=%dn", ARGC());
printf("ARGC(1) arg num=%dn", ARGC(1));
printf("ARGC(1, 2) arg num=%dn", ARGC(1, 2));
针对上面的调用,为了更好了解求值进程,让咱们测验一下手动对宏调用 ARGC(1) 打开看看:
ARGC(1)
__ARGC(1)
__ARGS(__ARGC_N(1,2,1))
(__ARGC_N(1,2,1)) ----> (__ARGC_N(1,2,N))
(1) ----> N = 1
ARGC(1) 应该返回 1。
完整测验成果输出:
ARGC() arg num=1
ARGC(1) arg num=1
ARGC(1, 2) arg num=2
为什么 ARGC() 输入 0 个参数时,核算成果不为 0,而输入其它数量的参数核算成果契合预期呢?核算进程还有待改进。
你能够自己手动打开一下 ARGC() 看看,当 ARGC() 输入 0 个参数时,__ARGC_N(__VA_ARGS__,2,1)
后边的逆序数字数量不足以匹配 N,此刻的 N 就强制匹配最后一个数字 1 了。为了处理这种反常匹配,当 N == 1 时,能够追加对第一个输入参数是否为空的判断:
#define __ARGC_N(_0,_1,N,...) N==1?(#_0)[0]!=0:N
#_0
用于将第一个参数转化成字符串,会占用一点空间,但不影响程序运转功率。(#_0)[0]
提取字符串的第一个字节。当 N == 1 时,假如第一个参数是空字符,(#_0)[0]!=0
返回 false,否则返回 true。false 转化成 0,true 转化成 1。
终究测验成果输出:
ARGC() arg num=0
ARGC(1) arg num=1
ARGC(1, 2) arg num=2
假如参数上限是 3 个,又怎样修正呢?
#define __ARGS(X) (X)
#define __ARGC_N(_0,_1,_2,N,...) N==1?(#_0)[0]!=0:N
#define __ARGC(...) __ARGS(__ARGC_N(__VA_ARGS__,3,2,1))
#define ARGC(...) __ARGC(__VA_ARGS__)
__ARGC_N(__VA_ARGS__,3,2,1)
后边的逆序最大数字 3 就决议了参数的上限个数为 3。当然修正参数上限,__ARGC_N 宏界说输入参数中的占位符 _0,_1,_2
个数需求对应参数上限的个数,占位符从 _0 开端。
假如输入的参数超过了上限呢?
printf("ARGC(1, 2, 3) arg num=%dn", ARGC(1, 2, 3));
printf("ARGC(1, 2, 3, 6) arg num=%dn", ARGC(1, 2, 3, 6));
printf("ARGC(1, 2, 3, 6, 9) arg num=%dn", ARGC(1, 2, 3, 6, 9));
成果输出:
ARGC(1, 2, 3) arg num=3
ARGC(1, 2, 3, 6) arg num=6
ARGC(1, 2, 3, 6, 9) arg num=6
输出的参数个数就等于超出上限的第一个参数值,不过,有言在先,参数个数有上限,而且合理设计的函数参数不应该过多,不必过度计较了。
未完待续,关注我查看更多精彩内容