参考:
在C/C++中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表如:
void foo(...);
void foo(pram_list, ...);
参数存放在内存的堆栈段中,在执行函数的时候,从最后一个入栈,因此栈底高地址,栈顶低地址。如:
void func(int x, float y, char z);
调用函数是,实参 z 先入栈,因此在内存中变量的存放顺序为 x, y, z. 因此理论上说:只要探测到任意一个变量的地址,并且知道其他变量类型,通过指针移位操作,可以找到其他所有的输入变量
#include
typedef char* va_list;
void va_start(va_list ap, prev_param); /*ANSI version*/
type va_arg(va_list ap, type);
void va_end(va_list, ap);
va_list ap;
// void foo(int arg1, int arg2, ...)
va_start(ap, arg2);
char para = va_arg( argp, char);
void va_end ( va_list ap );
一个完整的案例:
#include
#include
std::string format(const char* fmt, ...) {
va_list vl;
va_start(vl, fmt);
char buffer[2048];
vsnprintf(buffer, sizeof(buffer), fmt, vl);
va_end(vl);
return buffer;
}
void printArgs(int arg1, ...)
{
va_list args;
va_start(args, arg1);
int value = arg1;
while (value != -1)
{
std::cout << value << " ";
value = va_arg(args, int);
}
va_end(args);
}
int main()
{
printArgs(1, 2, 3, 4, 5, -1);
std::cout << format("rst: %s %d", "ans:", 1) << std::endl;
std::cout << format("rst: %s %d", "ans:", 2) << std::endl;
std::cout << format("rst: %s %d", "ans:", 2) << std::endl;
std::cout << format("rst: %s %d", "ans:", 3) << std::endl;
return 0;
}
1 2 3 4 5
rst: ans: 1
rst: ans: 2
rst: ans: 2
rst: ans: 3
先看一组常见的日志输出的宏:
#define INFOD(...) iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Debug, __VA_ARGS__)
#define INFOV(...) iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Verbose, __VA_ARGS__)
#define INFO(...) iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Info, __VA_ARGS__)
#define INFOW(...) iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Warning, __VA_ARGS__)
#define INFOE(...) iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Error, __VA_ARGS__)
#define INFOF(...) iLogger::__log_func(__FILE__, __LINE__, iLogger::LogLevel::Fatal, __VA_ARGS__)
调用方式:
INFOD("this is a log : %d %d %d", 1,2,3);