赞
踩
可变参数,顾名思义,其参数是可变的,具体指的是其参数的个数是可变的,即函数参数数目可变,其一般格式为:
type VarArgFunc(type FixedArg1, type FixedArg2,...)
其中,参数可分为两部分:数目固定参数和数目可变参数。函数至少需要一个固定参数,固定参数的声明和普通参数一样,可变参数由于个数不确定,声明时用“…”表示。注意,固定参数和可变参数共同构成参数列表。
要使用可变函数,需要引入头文件 #include “stdarg.h” ,要使用可变函数,需要先认识几个宏定义:
宏定义 | 作用 |
---|---|
va_list arg | 定义一个指向个数可变的参数列表指针 |
va_start(arg,n) | 使参数列表指针arg指向函数参数列表中的第一个可选参数 |
va_arg(arg,type) | 返回参数列表中指针arg所指的参数,返回类型为type,并使指针arg指向参数列表中的下一个参数 |
va_end(arg) | 清空参数列表,并置参数指针arg无效 |
下面,具体看看这几个宏定义在VS2008中的内容:
//定义一个指向个数可变的参数列表
typedef char* va_list; //定义va_list 是一个字符指针
可以看出,va_list arg的作用等同于char* arg。
//使参数列表指针ap指向函数参数列表中的第一个可选参数
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
//其中_INTSIZEOF(v)是指如果v是1,2,3,4个字节,则返回为4,如果为5,6,7.8个字节,则返回为8,类似于整型提升的作用
//v为可变参数的的前一个参数,取出该参数的地址,并对其做地址的提升,指向下一个参数(即指向第一个可变参数)
可以看出,va_start(arg,n)是使参数列表指针arg指向函数参数列表中的第一个可选参数。
//返回参数列表中指针ap所指的参数,返回类型为type,并使指针p指向参数列表中的下一个参数
#define va_arg(ap,t) (*(t *) ((ap +=_INTSIZEOF(t))-_INTSIZEOF(t)))
//清空参数列表,并置参数指针ap无效
#define va_end(ap) (ap = (va_list)0 )
下面,让我们以一个求任意个参数的平均值的函数为例:
#include <stdio.h>
#include <stdarg.h>
int average(int n, ...)
{
va_list arg;
int i = 0;
int sum = 0;
va_start(arg, n);
for(i=0; i<n; i++)
{
sum += va_arg(arg, int);
}
sum = sum/n;
va_end(arg);
return sum;
}
int main()
{
int a = 4;
int b = 5;
int c = 7;
int avg1 = average(2, a, c);
int avg2 = average(3, a, b, c);
printf("avg1 = %d\n", avg1);
printf("avg2 = %d\n", avg2);
return 0;
}
函数先出main()函数开始运行,执行到int avg1 = average(2, a, c);时调用average(int n, …),将实参2传给形参n,此时函数的栈帧如下图所示:
进入average函数后,先执行va_list arg;定义一个char*的变量arg,接着定义两个临时变量,在执行下一步:
va_start(arg, n);
//这句话定义为( arg = (va_list)&n + _INTSIZEOF(n) )
//取出n的地址,并使arg指向n一个下一个地址,即指向a。(此时arg指向a)
接着循环求和n次:
sum += va_arg(arg, int);
//va_arg(arg, int)表示:(*(int *) ((arg +=_INTSIZEOF(int))-_INTSIZEOF(int)))
//sum += (*(int *)((arg += 4)-4))
//每次拿到arg所指向的内容,并使arg向下偏移一个地址,为下次取内容做准备
求和之后,将其平均值赋给sum。
va_end(arg); //清空参数列表,并置参数指针arg无效
最后将sum返回。average函数调用完毕,完成对average函数的栈帧进行清栈。程序返回main()函数继续执行。
最后,小结一下,可变参数的函数就是:通过va_start初始化参数列表,然后使用va_arg从参数列表中取出你想要的参数,最后调用va_end执行清理工作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。