通常情况下,我们一个函数的参数个数是固定的,传多了会报错,少了有时也可能报错。 例如:
|
|
若是想调用abc()这个函数,必须传给他三个实参,函数才能正常执行。但是,我想调用一个函数,他的参数个数不确定呢?比如我们经常用的printf(),想在屏幕上打印一些东西。很多时候,参数个数都是不一样的,例如:
|
|
以上两个调用都能正常返回结果。其实他就是一个可变参数函数。
可变参数函数是指一个函数拥有不定引数,即是它接受一个可变量目的参数。在C语言中,C标准函式库的stdarg.h标头档定义了提供可变参数函数使用的宏。在C++,应该使用标头档cstdarg。
stdarg.h数据类型
| 类型名称 | 描述 | 相容 |
|---|---|---|
| va_list | 用来保存宏va_arg与宏va_end所需信息 | C89 |
stdarg.h宏
| 巨集名称 | 描述 | 相容 |
|---|---|---|
| va_start | 使va_list指向起始的参数 | C89 |
| va_arg | 检索参数 | C89 |
| va_end | 释放va_list | C89 |
| va_copy | 拷贝va_list的内容 | C99 |
| 函数printf()的声明是这样的:int printf(char *fmt, …); 后面“…”表示表示参数表中参数的数量和类型都是可变的。 我们看例子: |
|
|
va_list是一个类型,va_start,va_arg是宏,
va_start原型:va_start(va_list ap, lastarg); //lastarg是函数的最后一个有名参数(如果有多个有名参数)。 va_arg原型:类型 va_arg(va_list ap, 类型); //在va_arg里面指定什么类型,就返回什么类型 va_end原型:void va_end(va_list ap); //释放ap
va_list类型用于声明一个变量(我这里把他写成ap,其实是随意的,就像声明int一样,变量名称当然是随意的),该变量将依次引用各参数。
我们要用va_start初始化va_list才能正常使用。在上面例子里,参数中包含一个有名参数count,和不知道多少个无名的形参(如果有多个有名的参数,我们要把最右边也就是最后一个有名参数传给va_start,例如double average(int count1,int count2, …),我们应该这样va_start(ap, count2);)说是初始化,实际上是把va_list指向第一个无名参数。也就是说,ap被初始化为指向第一个无名参数的指针。
我们接着如何使用,这些没有名字的参数呢。我们可以用va_arg,我们用va_arg来决定返回对象的类型和指针移动的步长。va_arg(ap, double),指针是ap(用前必须用va_start初始化),第一次调用它,返回的是第一个无名参数,第二次调用它,返回的是第二个无名参数,以此类推。返回的参数,在形参上是用“…”代替的,每次调用va_arg必须指定一个返回的类型,例如上面的double。
我们在调用完可变参数后,应该使用va_end做一些必要的清理工作,例如va_end(ap);
(提示:我们看count这个参数是有名字的,既然有名字,我们就可以用它做一些工作,在上面的例子,他就是用来传递参数的个数,不过既然是普通的有名字参数,就可以用来做任何事情,不仅仅是传递参数个数的作用)
下面的这个例子有名参数就不是传递参数个数了,他是直接当做无名参数的一部分(这么说其实也不好,看个人理解)。
|
|
这个程序产生输出:
