va_start()va_end()和vsnprintf()函数应用

   通常我们需要在程序中输出部分日志信息,并把它记录到文件中。在这种情况下,使用printf可以为我们带了很大方便。因为printf却省情况下是向stdout即控制台屏幕输出信息,在GUI程序中,我们看不到printf的输出结果,但是我们可以将该输出重定向到指定的文件中。即使用freopen(“c://yourlog.log”, “a+”,stdout)或通过yourapp.exe > c:/yourlog.log完成输出重定向操作。
   刚开始接触后台代码的时候或者说正真接触一个项目后台前,看到用vsnprintf()格式化输出,觉得我靠,写那么多我没见过的函数,最终还是为了一个目的: printf()来输出,这不是绕一个圈子然后又回来么,简单的在需要日志输出的地方直接print就好了,不过现在觉得那么想是多么的不小白,每次输出的日志都不是单一的,在每个地方都单一的输出,看到那样的日志你会选择自杀,
还得从va_list,va_start(),va_end()和 ... 说起:
在c++中又函数重载功能,c语言中也是又类似功能的,如经常见到的  int fun(char *format, ... ),该函数的参数个数是未定的,以此实现了类似重载的功能,我们用的最多的printf() 函数就是这样实现的,现在来讲讲这个怎么用:
正如大家知道的那样,函数传入的参数是保存在栈中的(可以看看汇编,这个是怎样实现的),第一个参数在栈的最顶端,最后一个参数在栈的最底端,
对于函数void  fun(char *formt,...);进行调用fun("a","b","c","d","e","f","g");
va_list:复合类型,va_list  args;声明变量args,可以看作为一个指针 
va_start(args, formt):将args指向第一个参数"a"
va_arg(args, 参数类型):args指向下一个参数
va_end(args):将args置为无效
eg:
#include
#include
#include
void fun(int a,...)
{
va_list pp;
int n=1;
va_start(pp,a);
do
{
printf("第 %d 个参数 =%d\n",n++,a);
a=va_arg(pp,int);
}
while (a!=0);
}
int main()
{
fun(20,40,60,80,0);
return 0;
}
结果:
1 个参数 =20
2 个参数 =40
3 个参数 =60
4 个参数 =80
现在开始说vsnprintf():
头文件:#include
函数声明: int vsnprintf(char* str, size_t size, const char* format, va_list ap);
参数说明:
char *str [out],把生成的格式化的字符串存放在这里.
size_t size [in], str可接受的最大字节数,防止产生数组越界.
const char *format [in], 指定输出格式的字符串,它决定了你需要提供的可变参数的类型、个数和顺序。
va_list ap [in], va_list变量. va:variable-argument:可变参数
函数功能:将可变参数格式化输出到一个字符数组。
用法类似于vsprintf,不过加了size的限制,防止了内存溢出(size为str所指的存储空间的大小)。
返回值:执行成功,返回写入到字符数组str中的字符个数(不包含终止符),最大不超过size;执行失败,返回负值。 
eg:
int WriteErrorLog(const char* pszFmt,...)
{
static char szBuffer[4096];
va_list args;
va_start(args, pszFmt);
int nTmpLen = vsnprintf(szBuffer,4096,pszFmt, args);
va_end(args);
if (nTmpLen < 0)
{
return -1;
}
printf("ID = %d::%s \n",m_p->GetID(),szBuffer);
return 0;
}
这样你要输出的串就格式化到szBuffer中了,其实就是类似于自己改写printf(),使其可以嵌套使用,
这个问题是解决了,但是还有一个新问题就是szBuffer越界了怎么办,这里取的数字4096,如果在大点大到动态分配内存也会越界怎么办,
其实也是有办法解决的,是用一段汇编处理,将在下次笔记中记录讲解












你可能感兴趣的:(开发,c/c++)