返回值:成功返回输出的字节数(不包括最后的’\0’),失败返回-1。
vsprintf()与上面函数类似,就只列出函数原型了:
int vsprintf(
char *buffer,
const char *format,
va_list argptr
);
还有一个int _vscprintf(const char *format, va_list argptr );可以用来计算vsprintf()函数中的buffer字符串要多少字节的空间。
代码范例
下面就给出了自己实现的printf()函数(注1)与WriteLine()函数
int Printf(char *pszFormat, ...) { va_list pArgList; va_start(pArgList, pszFormat); int nByteWrite = vfprintf(stdout, pszFormat, pArgList); va_end(pArgList); return nByteWrite; } int WriteLine(char *pszFormat, ...) { va_list pArgList; va_start(pArgList, pszFormat); int nByteWrite = vfprintf(stdout, pszFormat, pArgList); if (nByteWrite != -1) putchar('\n'); //注2 va_end(pArgList); return (nByteWrite == -1 ? -1 : nByteWrite + 1); } |
调用与printf()函数相同。
再给出一个用可变参数来求和,遗憾的在C,C++中无法确定传入的可变参数的个数(printf()中是通过扫描'%'个数来确实参数的个数的),因此要么就要指定个数,要么在参数的最后要设置哨兵数值:
设置哨兵数值:
const int GUARDNUMBER = 0; //哨兵标识 //变参参数的个数无法确定,在printf()中是通过扫描'%'个数,在这通过设置哨兵标识来确定变参参数的终止 int MySum(int i, ...) { int sum = i; va_list argptr; va_start(argptr, i); while ((i = va_arg(argptr, int)) != GUARDNUMBER) sum += i; va_end(argptr); return sum; } |
可以这样的调用: printf("%d\n", MySum(1, 3, 5, 7, 9, 0));
但不可以直接传入一个0: printf("%d\n", MySum(0)); //error
指定个数:
int MySum(int nCount, ...) { if (nCount <= 0) return 0; int sum = 0; va_list argptr; va_start(argptr, nCount); for (int i = 0; i < nCount; i++) sum += va_arg(argptr, int); va_end(argptr); return sum; } |
调用时第一个参数表示后面参数的个数如:
printf("%d\n", MySum(5, 1, 3, 5, 7, 9));
printf("%d\n", MySum(0));
代码所用的头文件:
#include <stdarg.h>
#include <stdio.h>
可变参数的使用方法远远不止上述几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃。
可变参数的原形理涉及到调用函数时参数的入栈问题,这个下次再开一篇进行专门的探讨。
注1. 网上有不用vfprintf()自己解析参数来实现printf()的,但很少能将功能做到与printf()相近(实际上能完全熟悉printf()的人已经就不多,不信的话可以先看看《C陷阱与缺陷》了解printf()很多不太常用的参数,再去Microsoft Visual Studio\VC98\CRT\SRC中查看OUTPUT.C对printf()的实现)。
注2. 如果输出单个字符 putchar(ch)会比printf(“%c”, ch)效率高的多。在字符串不长的情况下,多次调用putchar()也会比调用printf(“%s\n”, szStr);的效率高。在函数大量调用时非常明显。