在C/C++中, 经常会接触到变参, 也就是va(variable argument), 我们的printf函数就是这么做的。 搞过软件开发的人肯定知道, 几乎所有软件的日志函数, 都会采用变参。 下面, 我们来一起聊聊va_list、va_start、va_arg、va_end
看一下这些东东在VC++6.0中的定义:
#ifndef _VA_LIST_DEFINED
#ifdef _M_ALPHA
typedef struct {
char *a0; /* pointer to first homed integer argument */
int offset; /* byte offset of next parameter */
} va_list;
#else
typedef char * va_list;
#endif
#define _VA_LIST_DEFINED
#endif
#ifdef _M_IX86
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
#elif defined(_M_MRX000)
首先, va_list实际上就是char *类型, 别无其他。
再看看va_start(ap,v); ap指向变数, v表示某个特定变量, 根据程序传入值来确定。 如此一来, ap指向了v的下一个值, 只要v值传的合理, ap也就是第一个变参。
再看va_arg(ap,t), ap指向变参,t是可变参数的类型。 va_arg(ap,t)的返回值是:将ap指向的地址以t类型来解读后的值。 注意, ap会自增。
再瞄瞄va_end(ap) ; 这个很俗套了, 可以看到, 是指针清零的操作。
我们看个简单的程序哈:
#include <iostream>
#include <string>
#include <fstream>
#include <cstdarg>
using namespace std;
void fun(const char *format, ...)
{
va_list args;
va_start(args, format);
cout << va_arg(args, char *) << endl;
cout << va_arg(args, int) << endl;
cout << va_arg(args, char *) << endl;
cout << va_arg(args, int) << endl;
va_end(args);
}
int main()
{
fun("%s%d, %s%d", "practice", 1, "practice", 2);
return 0;
}
结果:
practice
1
practice
2
再来看一个哈:
#include <iostream>
#include <string>
#include <fstream>
#include <cstdarg>
using namespace std;
void fun(int n, ...)
{
va_list args;
va_start(args, n);
cout << va_arg(args, int) << endl;
cout << va_arg(args, int) << endl;
cout << va_arg(args, int) << endl;
cout << va_arg(args, int) << endl;
cout << va_arg(args, int) << endl;
va_end(args);
}
int main()
{
fun(0, 1, 2, 3, 4, 5);
return 0;
}
结果:
1
2
3
4
5
稍微修改一下程序:
#include <iostream>
#include <string>
#include <fstream>
#include <cstdarg>
using namespace std;
int fun(int n, ...)
{
va_list args;
va_start(args, n);
int i = 0;
int sum = 0;
for(i = 0; i < n; i++)
{
sum += va_arg(args, int);
}
va_end(args);
return sum;
}
int main()
{
cout << fun(5, 1, 2, 3, 4, 5) << endl;
return 0;
}
结果:15
就这样。