可变参数函数实现的步骤如下:
-
1.在函数中创建一个va_list类型变量
-
2.使用va_start对其进行初始化
-
3.使用va_arg访问参数值
-
4.使用va_end完成清理工作
接下来我们来实现一个变长参数函数来对给定的一组整数进行求和。程序清单如下:
#include <stdio.h> /*要使用变长参数的宏,需要包含下面的头文件*/ #include <stdarg.h> /* * getSum:用于计算一组整数的和 * num:整数的数量 * * */ int getSum(int num, ...) { va_list ap;//定义参数列表变量 int sum = 0; int loop = 0; va_start(ap, num); /*遍历参数值*/ for (; loop < num ; loop++) { /*取出并加上下一个参数值*/ sum += va_arg(ap, int); } va_end(ap); return sum; } int main(int argc, char *argv[]) { int sum = 0; sum = getSum(5, 1, 2, 3, 4, 5); printf("%d\n", sum); return 0; }
上面的小程序接受变长参数,第一个参数表明将要计算和的整数个数,后面的参数是要计算的值。
编译运行可得结果:15。
总结
通过前面的分析和示例,我们来做一些总结
-
变长参数实现的基本原理
对于x86来说,函数参数入栈顺序为从右往左,因此,在知道第一个参数地址之后,我们能够通过地址偏移获取其他参数,虽然x86-64在实现上略有不同,但`对于开发者使用来说,实现变长参数函数没有32位和64位的区别。 -
变长参数实现注意事项
1.…前的参数可以有1个或多个,但前一个必须是确定类型。
2.传入参数会可能会出现类型提升。
3.va_arg的type类型不能是char,short int,float等类型,否则取值不正确,原因为第2点。
4.va_arg不能往回取参数,但可以使用va_copy拷贝va_list,以备后用。
5.变长参数类型注意做好检查,例如可以采用printf的占位符方式等等。
6.即便printf有类型检查,但也要注意参数匹配,例如,将int类型匹配%s打印,将会出现严重问题。
7.当传入参数个数少于使用的个数时,可能会出现严重问题,当传入参数大于使用的个数时,多出的参数不会被处理使用。
8.注意字节对齐问题。
变长参数实现
经过前面的理解分析,我们知道,正是由于参数从右往左入栈(但是要注意的是,对于x86-64,它的参数不是完全从右往左入栈,且参数可能不在一个连续的区域中,它的变长参数实现也更为复杂,我们这里不展开)可以实现变长参数。当然了,这一切,C已经有现成可用的一些东西来帮我们实现变长参数。
它主要通过一个类型(va_list)和三个宏(va_start、va_arg、va_end)来实现
va_list :存储参数的类型信息,32位和64位实现不一样。
void va_start ( va_list ap, paramN );
参数:
ap: 可变参数列表地址
paramN: 确定的参数
功能:初始化可变参数列表,会把paraN之后的参数放入ap中
type va_arg ( va_list ap, type );
功能:返回下一个参数的值。
void va_end ( va_list ap );
功能:完成清理工作。
转载自:
https://mp.weixin.qq.com/s/CbXT6G0CHzp0BG0gS-hprw