#include
//...表示不定参,__VA_ARGS__使用不定参
// __FILE__ 文件名
//__LINE__ 行号
//__VA_ARGS__ 用于在宏替换部分中,表示可变参数列表;
//当可变参数的个数为0时,##起到把前面多余的","去掉的作用,否则会编译出错
#define LOG(fmt,...) printf("[%s:%d]" fmt,__FILE__,__LINE__,##__VA_ARGS__);
int main()
{
LOG("可变参数列表");
//最终展开的代码相当于printf("[%s:%d]" "可变参数列表",__FILE__,__LINE__)
//如果不加##,会报错
//printf("%d""nihao",6);可以编译通过
return 0;
}
在这里我之前一直有一个误区:
1.我认为printf("%d""nihao",6);
是不合法的,因为格式化参数后面没有加,
,直到今天认识了可变参数宏,才认识到
2."%d""nihao"
会自动连接
使用之前需要自己定义一个va_list 变量
va_start()函数 语法
void va_start(va_list ap,param);
参数ap为参数自身;
参数param为第一个参数。
va_arg()函数用于调用可变参数列表
type va_arg(va_list ap,type);
参数ap为可变参数自身;
参数type为要获取的参数的指定类型,返回这个指定类型的值,并把ap的位置指向变参表的下一个变量位置
va_end()函数用于停止使用可变参数。
void va_end(va_list ap);
参数ap为参数自身。
简单使用
void print(int cnt,...)
{
va_list ap;
va_start(ap,cnt);//获取cnt参数之后的第一个参数的地址即第一个不定参地址
for(int i=0;i<cnt;++i)
{
int num=va_arg(ap,int);//获取不定参
printf("param[%d]:%d\n",i,num);
}
va_end(ap);//使用完将ap指针置空
}
以printf(const char* format,…)
为例
int vasprintf(char **strp, const char *fmt, va_list ap);
vasprintf 是一个 C 库函数,它可以通过可变参数创建一个格式化的字符串,并将其存储在动态分配的内存中。它的使用方法与 printf 类似,但它不会将结果打印到标准输出流中,而是将其存储在一个指向字符数组的指针中
void MyPrint(const char *fmt, ...)
{
va_list ap;
va_start(ap,fmt);
char* res;
int ret=vasprintf(&res,fmt,ap);
if(ret !=-1)
{
printf(res);
free(res);
}
va_end(ap);
}
需要借助C++11内的万能引用与完美转发及可变参数模版包
#include
#include
#include
#include
//特化
void CgagaPrint()
{
std::cout<<std::endl;
}
template<class T,class ...Args>
void CgagaPrint(const T& v,Args&& ...args)
{
std::cout<<v;
if((sizeof ...(args))>0)
{
//完美转发
CgagaPrint(std::forward<Args>(args)...);
}
else
{
CgagaPrint();
}
}
int main()
{
CgagaPrint("nihao",6,5,4);
}