C 语言允许定义参数数量可变的函数,这称为可变参数函数。这种函数需要固定数量的强制参数,后面是数量可变的可选参数。
常见的可变参数函数
int printf(const char* format,…)
int scanf(const char *format,…)
固定参数 format ,可选参数用“...”最为参数占用符
任何一个可变参数的函数都可以分为两部分:固定参数和可选参数。至少要有一个固定参数,其声明与普通函数参数声明相同;可选参数由于数目不定(0个或以上),声明时用"…"表示。固定参数和可选参数共同构成可变参数函数的参数列表。
// 函数add() 计算可选参数之和
// 参数:第一个强制参数指定了可选参数的数量,可选参数为double类型
// 返回值:和值,double类型
double add( int n, ... )
{
int i = 0;
double sum = 0.0;
va_list argptr;
va_start( argptr, n ); // 初始化argptr
for ( i = 0; i < n; ++i ) // 对每个可选参数,读取类型为double的参数,
sum += va_arg( argptr, double ); // 然后累加到sum中
va_end( argptr );
return sum;
}
在上面的例子中,用到了va_list ,va_start,va_arg,va_end 包含头文件
va_list :其实就是通过typedef 定义的一个指针类型,它用来定义一个指针。
va_start:其实就是为了获取可选参数的地址,然后保存在第一个参数中。它有两个参数,一个参数是va_list 类型的,用来存放第一个可选参数的地址。另一个参数是与可选参数相邻的那个强制参数。其实在程序的栈中,函数的所有参数都是在内存中连续分布的,所以可以通过强制参数的地址来获取可选参数的地址,然后保存在第一个参数中
va_arg:这个宏取得 type 类型的可变参数值。该函数有两个参数,第一个参数是当前可变参数的地址,第二个参数是当前可变参数的类型。通过地址和类型来确定可变参数的值,然后返回。这个函数调用过后,第一个参数的值会变化,它会指向参数列表中下一个参数。
va_end:必须和va_start 配合使用,使用 va_start 宏的函数中退出之前,必须调用一次 va_end 宏。相当于释放了内存。
个可变参数的宏,它使得可以在宏定义中使用可变参数列表,可变参数的个数最少为1,否则编译会出错。
//用法如下,在宏定义中替代 ... :
#define my_print2(fmt,...) printf(fmt,__VA_ARGS__)
此外还有一个 ##__VA_ARGS__ ,它可以允许可变参数的个数为0个。
#define my_print2(fmt,...) printf(fmt,__VA_ARGS__)
my_print2("i=%d,j=%d\n",i,j) //正确打印
my_print2("iiiiiii\n") //编译失败 只有一个参数,可变参数的个数为0
//改为:
#define my_print2(fmt,...) printf(fmt,##__VA_ARGS__)
my_print2("iiiiiii\n")
vsprintf与vsnprintf的用法差不多,区别在于vsnprintf限制了最大的转换长度,可以防止越界。一般选用vsnprintf。
int vsprintf (char * s, const char * format, va_list arg );
将可变参数列表的格式化数据写入字符数组s中
s:这是指向一个字符数组的指针,该数组存储了字符串
format:要格式化输出的字符串
arg:可变参数列表
返回值:如果成功,则返回写入的字符总数,否则返回一个负数
用法:
int vspfunc(char *format, ...)
{
va_list aptr;
int ret;
va_start(aptr, format);
ret = vsprintf(buffer, format, aptr);
va_end(aptr);
return(ret);
}
int main()
{
int i = 5;
float f = 27.0;
char str[50] = "runoob.com";
vspfunc("%d %f %s", i, f, str);
printf("%s\n", buffer);
return(0);
}
int vsnprintf(char *s, size_t n, const char *format, va_list arg)
s:这是指向一个字符数组的指针,该数组用来存储字符串
n:在缓冲区中使用的最大字节数。生成的字符串的长度至多为n-1,为额外的终止空字符留下空间
format:要格式化输出的字符串
arg:可变参数列表
返回值:如果成功,则返回写入的字符总数,不包括终止空字符,否则返回一个负数
用法:
void test(const char * format, ...)
{
char buf[4069];
va_list list;
va_start(list, format);
vsnprintf(buf, 4069, format, list);
va_end(list);
printf("%s\n", buf);
}