想要函数使用可变参数,那就必须要包含stdarg.h
这个头文件,简单就不说了,我们重新来看看可变参数的定义和使用吧。
1.声明可变参数
可变参数的声明有两点
使用‘…’来代表可变参数可变参数之前必须有一个命名的参数简单说就是如果你想声明一个可变参数的函数,那么有两种形式
func(...) //错误,前面必须有一个命名的参数func(xxx,...) //正确,xxx可以用任意的参数代替,比如char *name,int i都可以2.定义可变参数
可变参数的定义和声明相同,两者保持一致即可
3.可变参数的使用
要使用可变参数,主要会用到下列几个函数
#include <stdarg.h>void va_start(va_list ap, last);type va_arg(va_list ap, type);void va_end(va_list ap);void va_copy(va_list dest, va_list src);这里四个函数是参考man手册上的,最后的va_copy
没有用过,不太清楚什么情况下需要使用,麻烦各位在留言赐教 剩下的三个我们来一个一个看,这里举个简单的例子方便讲解
可以看到,要使用可变参数,首先需要定义一个va_list
类型的变量,这个变量就相当于是指向可变参数列表的指针,通过va_start
函数将这个指针赋值,后面就可以通过va_arg
来获取每一个参数。
va_arg
的函数原型里面有个type
,这个type
类型怎么理解呢? 大家可以这样理解,因为可变参数是没有声明参数类型的,那么编译器怎么去检测到底类型是否匹配呢?最简单的办法就是向上提升,比如
由于默认肯定会向上提升,所以一定要尽量避免以下类型的参数 type绝对不能为以下类型:
char、signed char、unsigned charshort、unsigned shortsigned short、short int、signed short int、unsigned short intfloat因此在示例中,第一个int
类型的数字我用int
类型接收,第二个字符我依然使用int
类型来接收,第三个字符串就必须使用char *
类型的接收,第四个浮点型使用double
类型来接收,如果你不小心写错了类型,系统的提示如下(这里我把示例中的double改成了float)
最后的va_end
就相当于是结束标记,一个va_start
必须和一个va_end
对应起来使用才可以。
使用的话我想大家应该都会,那具体原理是什么样的呢? 要搞清楚原理,首先需要知道参数到底是怎么传递进来的,事实上,在进程中,堆栈地址时由高向低分配的,在调用参数的时候,首先入栈的函数参数,接下来是函数的返回地址,再下来是函数的执行代码,而参数的入栈顺序是先入最后一个参数,最后入第一个参数
如上图所示,参数在堆栈的排列是从高地址向低地址的,实际上具体是宏定义如下
typedef char * va_list; // x86平台下va_list的定义#define va_start(ap, v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址#define va_arg(ap, t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效这里有个宏_INTSIZEOF
需要特别介绍下,这个宏是为了求出变量所占内存空间的大小,具体实现如下
网上有位大神对这个函数又深刻的理解,大家可以去看看他的文章_INTSIZEOF(n)这个函数简单说就是把n
转化成int
的整数倍,来实现格式对齐,明白了这里,我们接着往下看
va_start
这个应该很好理解,就是说固定参数的地址加上他本身的内存大小,结合上面的图也就是第一个可变参数的地址,这样ap
就指向了第一个可变参数,后面我们通过ap
就可以得到其他的参数
va_arg
这个宏写的有些复杂,我们需要把它拆成两部分看 1. ap += _INTSIZEOF(t); // 此时指针ap已经指向下一个参数了 /* ap减去当前参数的大小得到当前参数的地址,再把地址强制类型转换后返回它的值 */ 2. return (t )( ap - _INTSIZEOF(t)) 通过第一步我们让指针ap
指向了后一个参数,通过第二步返回了当前的参数
va_end
这个宏很简单,就是清空了指针,记着需要和va_start
配套使用
看了C语言的具体实现,不得不感叹,大神们真的是把指针使用的淋漓尽致,不过任何事情都有两方面,这样做虽然高效快捷,但同时也留下了不小的安全隐患
参考文档 深入浅出va函数 关于va_arg中的type
新闻热点
疑难解答