[C]va_list可变长参数的使用
一、概述
运用标准C的头文件stdarg.h提供的宏可以实现函数的自定义传参个数;
二、语法
1.va_list是一个可变长参数类型,在使用可变长参数的函数中可以定义1个或多个va_list类型参数,等待va_start初始化后使用;
va_list parg_1;
va_list parg_2;
2.va_start作用是给va_list类型变量绑定一个起始值
宏原型:
void va_start(va_list ap, last);
ap是va_list类型变量;
last是函数的最后一个固定参数(由于可变长函数的声明语法,参数部分必须至少包含一个固定传参);
va_start执行后,该ap的指针将会指向变参的起始位置;
3.va_copy作用是复制一份初始化后的va_list变量,通常用在调用va_start之后;
void va_copy(va_list ap2, va_list ap1);
ap2是复制到达的va_list变量;
ap1是被复制的va_list变量;
复制完毕后,两个变量的变长参数偏移量不相干;
4.va_arg被调用后将会返回当前指针偏移量的参数,随之指针将会移动到下一个变参的位置
type va_arg(va_list ap, type);
ap是被初始化后的va_list变量;
type是,除以下类型之外的其他类型
type绝对不能为以下类型:
——char、signed char、unsigned char
——short、unsigned
short
——signed short、short int、signed short int、unsigned short int
——float
这是因为C标准中有一个默认参数提升(default argument promotions)规则。
注意:有时候因为代码问题(例如类型错误)导致va_arg返回了错误的结果,但是也不会影响va_arg的下一次取参哦,这是因为指针的偏移是通过变参的底层size属性获取的
5.va_end用于结束整个取参流程
void va_end(va_list ap);
二、示例
1.通过代码说明printf的原理
#include <stdio.h> #include <string.h> #include <stdarg.h> void myPrintf(const char *format, ...); int main(void) { char str_1[] = "January & February"; double d_1 = 0.25; int i_1 = 16; char str_2[] = "March & April"; int i_2 = 528; myPrintf(str_1, d_1, i_1, str_2, i_2); } void myPrintf(const char *format, ...) { printf("%s\n", format); va_list parg; va_start(parg, format); printf("%.6lf\n", va_arg(parg, double)); printf("%d\n", va_arg(parg, int)); printf("%s\n", va_arg(parg, char*)); printf("%d\n", va_arg(parg, int)); va_end(parg); }
输出:
0.250000
16
March & April
528
说明:
C自带的printf函数是根据第一个参数format的占位符解析出后面的变参个数和类型,通过va_arg迭代去获取变参再填充到占位符上输出。解析占位符并不是一件简单的工作,所以这里的代码只是大致说明了一下它的原理;
2.求平均数
#include <stdio.h> #include <stdarg.h> double average(double v1, double v2, ...); int count = 0; int main(void) { printf("Average = %.6lf\n", average(0.2, 3.5, 108.625, (double)56, 0.3, 0.0)); } double average(double v1, double v2, ...) { va_list parg; double sum = v1 + v2; double value = 0.0; int count = 2; va_start(parg, v2); while((value = va_arg(parg, double)) != 0.0) { printf("Item = %.6lf\n", value); sum += value; ++count; } va_end(parg); return sum/count; }
说明:
此代码在固定前两个参数的前提下,后面使用变参