C语言支持可变参数,即参数个数不固定,典型的函数如printf, scanf等可以接受数量不定的参数。
如,printf("one parameter");printf("two parameter: %d", a);printf("three parameter: %d, %s", a, s);
上面三个printf分别接收1,2,3个参数。来看一下printf的原型:
#include <stdio.h>
int printf(const char *format, ...);
由此可以看出,printf除接收一个固定的参数format以外,后面的参数用"..."表示,即"..."表示可以接受0个或多个参数。
一个类型三个宏
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
va_list类型大部分场合下为char *,即typedef char * va_list;
va_start 接收两个参数,一个是va_list类型的变量,一个是省略号前最后一个有名字的参数,该宏实际做了初始化工作。
va_arg 接收两个参数,一个是初始化后的va_list变量,一个是返回的参数类型,每一次调用都会返回下一个参数。
va_end 接收va_list变量,进行清理工作。
实现可变参数函数很简单,三步走就可以:va_start初始化,va_arg取参数,va_end清理现场。
例子
下面程序实现了两个可变参数函数,maxInt 接受n个整数,返回最大的数;maxStr接受n个字符串,返回最长的那个。
#include <stdarg.h>
#include <iostream>
using namespace std;
int maxInt(int num, ...);
std::string maxStr(int num, ...);
int main()
{
int n = maxInt ( 5, 5, 6 ,3 ,8 ,5);
cout << n;
std::string m = maxStr(5, "a", "ab", "abc", "abcd", "abcde");
std::cout << m << std::endl;
return 0;
}
int maxInt(int num, ...)
{
int m = 0;
va_list ap;
va_start(ap, num);
for ( int i= 0; i< num; i++ )
{
int t = va_arg (ap, int);
if ( t > m )
{
m = t;
}
}
va_end (ap);
return m;
}
std::string maxStr(int num, ...)
{
std::string ret;
va_list ap;
va_start(ap, num);
for(int i = 0; i < num; i++)
{
std::string l_tmp = va_arg(ap, char*);
std::cout << "get param: " << l_tmp << std::endl;
if(l_tmp.length() > ret.length()) ret = l_tmp;
}
va_end(ap);
return ret;
}
其他
1.可变参数函数必须要有一个固定参数吗?
不一定,有的环境下va_start只接收一个va_list类型参数,这种情况下可变参数函数或许可以没有参数,没有验证过。
2.关于va_copy
va_copy 原型是void va_copy(va_list dest, va_list src);提供了两个va_list拷贝功能。其不是标准C提供的,而是在C99中定义的,可以选择使用。