可变参数的使用

通常情况下,我们一个函数的参数个数是固定的,传多了会报错,少了有时也可能报错。
例如:

1
int abc(int a, int b, int c);

若是想调用abc()这个函数,必须传给他三个实参,函数才能正常执行。但是,我想调用一个函数,他的参数个数不确定呢?比如我们经常用的printf(),想在屏幕上打印一些东西。很多时候,参数个数都是不一样的,例如:

1
2
printf(“%d%d”, a, b);
printf(“%d%d”,a, b, c);

以上两个调用都能正常返回结果。其实他就是一个可变参数函数

可变参数函数是指一个函数拥有不定引数,即是它接受一个可变量目的参数。在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, …); 后面“…”表示表示参数表中参数的数量和类型都是可变的。 我们看例子:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdarg.h>//必须的头文件
double average(int count, ...)
{
va_list ap;
int j;
double tot = 0;
va_start(ap, count); //使va_list指向起始的参数
for(j=0; j<count; j++)
tot+=va_arg(ap, double); //检索参数,必须按需要指定类型
va_end(ap); //释放va_list
return tot/count;
}

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这个参数是有名字的,既然有名字,我们就可以用它做一些工作,在上面的例子,他就是用来传递参数的个数,不过既然是普通的有名字参数,就可以用来做任何事情,不仅仅是传递参数个数的作用)

下面的这个例子有名参数就不是传递参数个数了,他是直接当做无名参数的一部分(这么说其实也不好,看个人理解)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdarg.h>
void printargs(int arg1, ...) /* 输出所有int类型的参数,直到-1结束 */
{
va_list ap;
int i;
va_start(ap, arg1);
for (i = arg1; i != -1; i = va_arg(ap, int))
printf("%d ", i);
va_end(ap);
putchar('n');
}
int main(void)
{
printargs(5, 2, 14, 84, 97, 15, 24, 48, -1);
printargs(84, 51, -1);
printargs(-1);
printargs(1, -1);
return 0;
}

这个程序产生输出:

坚持原创技术分享,您的支持将鼓励我继续创作!