我们常用的打印函数printf就是一个可变参数的函数,参数个数并不是固定的,函数原型为:
int printf(const char *format, ...);
这就是一个典型的变参函数,其中的变参用三个点 ... 表示。
那么该如何编写自己的变参函数呢,这就要用到处理变参的三个方法:va_start, va_arg, va_end , 这三个方法包含在头文件 stdarg.h 中,这三个方法的原型为:
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
下面用一个简单的代码来演示下:
#include <stdio.h>
#include <stdarg.h>
//求narg个整数的和
int sum(int narg, ...)
{
va_list ap; //首先定义一个va_list类型的变量
va_start(ap, narg); //va_start 的第一个参数为va_list变量,第二个参数为函数的最后一个固定参数
int s = 0, i, tmp;
for(i = 0; i < narg; i++)
{
tmp = va_arg(ap, int); // 每次调用迭代出一个可变参数值, 该函数的第二个参数要求指明变量的类型
s += tmp;
}
va_end(ap); //用va_end结束迭代, ap is undefined
return s;
}
int main(void)
{
printf("1+2 = %d\n", sum(2, 1,2));
printf("1+...+5 = %d\n", sum(5, 1,2,3,4,5));
printf("1+...+10 = %d\n", sum(10, 1,2,3,4,5,6,7,8,9,10));
return 0;
}
执行结果:
1+2 = 3
1+...+5 = 15
1+...+10 = 55
由于va_start函数的第二个参数是函数的最后一个固定参数名,所以C语言中的变参函数至少需要一个固定参数,如有需要,变参函数可以多次循环迭代出变参值:
#include <stdio.h>
#include <stdarg.h>
void myprint(int narg, ...)
{
va_list ap;
char *str;
int i;
va_start(ap, narg);
for(i = 0; i < narg; i++)
{
str = va_arg(ap, char *); //参数类型为char *
printf("第 %d 个参数为:%s\n", i, str);
}
va_end(ap);
printf("\n");
// 再循环取一次可变参数
va_start(ap, narg);
for(i = 0; i < narg; i++)
{
str = va_arg(ap, char *); //参数类型为char *
printf("第 %d 个参数为:%s\n", i, str);
}
va_end(ap);
}
int main()
{
myprint(2, "hello", "world");
return 0;
}
执行结果:
第 0 个参数为:hello
第 1 个参数为:world
第 0 个参数为:hello
第 1 个参数为:world
C语言中还提供了直接使用变参的函数,
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
只需传入va_list ap即可,不需要自己迭代参数值,例如
#include <stdio.h>
#include <stdarg.h>
void myprint(int narg, ...)
{
va_list ap;
va_start(ap, narg);
vprintf("%s, %s \n", ap);
va_end(ap);
}
int main()
{
myprint(2, "hello", "vprintf");
return 0;
}
That's all!