可变参数列表详解
2017-04-23 22:14
288 查看
一、定义及表达方式
可变参数,顾名思义,其参数是可变的,具体指的是其参数的个数是可变的,即函数参数数目可变,其一般格式为: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无效 |
//定义一个指向个数可变的参数列表 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执行清理工作。
相关文章推荐
- 详解可变参数列表
- C语言可变参数列表详解
- 详解可变参数列表
- 可变参数列表详解(内附求平均数和实现简单的printf)
- Java可变参数列表详解
- C语言中的可变参数列表使用详解(转)
- java5特性(可变参数列表)
- C的可变参数列表(转)
- 可变参数列表需要注意的问题
- 【C/C++】sprintf中如何将容器作为可变参数列表传入
- 可变参数列表及printf函数的实现
- wordpress分类列表函数:wp_list_categories 参数详解
- [C语言]利用stdarg.h来实现可变参数列表
- 可变参数列表
- 一个fprintf的简单封装实例(vsprintf,va_start(),+va_arg(),+va_end()可变参数列表)
- 又学了一招——JAVA中三个点(...)的运算符,表示可变参数列表
- 可变参数列表的函数调用 va_list va_start va_arg va_end
- C和Java中函数的可变参数列表
- 可变参数列表(va_list,va_arg,va_copy,va_start,va_end)
- c语言中参数列表可变的函数写法,如printf