根据微软的文档vsnprintf https://msdn.microsoft.com/en-us/library/1kt27hek.aspx,至少从 2003 版 Visual Studio 开始,该函数就是 C(++) 运行时库的一部分。
int vsnprintf( char *buffer, // Storage location for output
size_t count, // Maximum number of characters to write
const char *format, // Format specification
va_list argptr ) // Pointer to list of other arguments
我问:哪些版本的 Visual Studio 是vsnprintf
符合 C99 标准 (ISO/IEC 9899:1999) 的 x86 和 x64 捆绑 C(++) RTL 实现,假设
-
#define _CRT_SECURE_NO_WARNINGS
之前执行#include <stdio.h>
,这是现代版本的 Visual Studio RTL 所必需的;
- if
count
大于零,那么buffer
是一个指向(至少)的指针count
可写字符;
- 格式不是
NULL
并符合Microsoft 的格式规范语法 https://msdn.microsoft.com/en-us/library/56e442dc.aspx适用于 RTL 的特定版本;
- 的价值
count
并且要生成的字符数都足够小以适应类型int
;
我们希望一致性包括(除了标称输入的基本功能之外)这些要求(由标准的规范暗示)snprintf
, which vsnprintf
参考):
- 不产生未定义的行为(包括调用Microsoft 的无效参数处理程序 https://msdn.microsoft.com/en-us/library/ksazx244.aspx)在上述假设下;
- 返回要写入的长度(不包括终止空字符)
buffer==NULL
and count==0
,从而允许飞行前确定输出的长度;
- 始终用终止空字符填充输出字符串
buffer!=NULL
and count>0
并且返回的结果是非负的,包括由于小而截断的输出count
.
注意以下comment https://stackoverflow.com/q/34996375/903600#comment57721538_34996375: 我愿意承认自己的不足restrict
限定符仍然在大多数符合标准的允许范围内。
该文档对于 (3.) 的一致性不明确;据我所知,与 Visual Studio Community 2015 捆绑在一起的实现很好,但并非全部都是这样。
如果末尾有空间(即要写入的字符数小于count
),缓冲区将以空终止。
该文档还明确暗示了这一点vsnprintf
不符合 C99 标准的 (1.) 和 (2.) 时buffer==NULL
and count==0
;但文档的这些部分似乎是错误的:
如果要写入的字符数大于count
,这些函数返回 -1 表示输出已被截断。
If buffer
or format
is NULL
, or if count
小于或等于零,这些函数调用无效参数处理程序
测试代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdarg.h>
int f( char *buffer,
size_t count,
const char *format,
...
)
{
va_list vArgs;
int vRes;
va_start(vArgs, format);
vRes = vsnprintf( buffer, count, format, vArgs);
va_end(vArgs);
return vRes;
}
int main(void)
{
char vBuf[6];
int j, count;
#ifdef _MSC_VER
printf("_MSC_VER = %ld\n",(long)(_MSC_VER));
#else
printf("_MSC_VER is undefined\n");
#endif
printf("f(NULL,0,\"%%d\",777):%3d\n", f(NULL,0,"%d",777));
for(count=0 ;count<=sizeof(vBuf); ++count)
{
for(j=0; j<sizeof(vBuf)-1; ++j)
vBuf[j] = '!';
vBuf[j] = 0;
j = f(vBuf,count,"%d",777);
printf("f(vBuf,%d,\"%%d\",777):%3d vBuf: \"%s\"\n",count,j,vBuf);
}
return 0;
}
在我安装的 Visual Studio Community 2015 下提供
_MSC_VER = 1900
f(NULL,0,"%d",777): 3
f(vBuf,0,"%d",777): 3 vBuf: "!!!!!"
f(vBuf,1,"%d",777): 3 vBuf: ""
f(vBuf,2,"%d",777): 3 vBuf: "7"
f(vBuf,3,"%d",777): 3 vBuf: "77"
f(vBuf,4,"%d",777): 3 vBuf: "777"
f(vBuf,5,"%d",777): 3 vBuf: "777"
f(vBuf,6,"%d",777): 3 vBuf: "777"
并在安装了 Visual Studio 2008 后(我相信 SP1 + PSDK 7.1)
_MSC_VER = 1500
f(NULL,0,"%d",777): 3
f(vBuf,0,"%d",777): -1 vBuf: "!!!!!"
f(vBuf,1,"%d",777): -1 vBuf: "7!!!!"
f(vBuf,2,"%d",777): -1 vBuf: "77!!!"
f(vBuf,3,"%d",777): 3 vBuf: "777!!"
f(vBuf,4,"%d",777): 3 vBuf: "777"
f(vBuf,5,"%d",777): 3 vBuf: "777"
f(vBuf,6,"%d",777): 3 vBuf: "777"
请注意缺少终止空字符,特别是count==3
,即使输出为正。