从什么版本的 Visual Studio 开始,vsnprintf 最符合标准?

Starting at what version of Visual Studio is vsnprintf mostly standard-conformant?

根据 Microsoft's documentation for vsnprintf,该函数是 C(++) 运行-Time 库的一部分,至少从 Visual Studio.

的 2003 版开始
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 的哪个版本是符合 C99 标准的 x86 和 x64 捆绑 C(++) RTL 的 vsnprintf 实现(ISO/IEC 9899:1999), 假设

并且我们希望一致性包括(除了标称输入的基本功能之外)这些要求(由 snprintf 的标准规范暗示,vsnprintf 引用):

  1. 在上述假设下不会产生未定义的行为(包括调用Microsoft's invalid parameter handler);
  2. buffer==NULLcount==0时返回要写入的长度(不包括终止空字符),从而允许飞行前确定输出的长度;
  3. 总是在 buffer!=NULLcount>0 时用终止空字符填充输出字符串并且返回的结果是非负数,包括由于小 count 导致的截断输出。

注意 之后:我愿意承认缺少 restrict 限定词,因为大多数符合标准的人仍然在允许范围内。


文档对 (3.) 的一致性含糊不清;据我所知,与 Visual Studio Community 2015 捆绑在一起的实现很好,但并非所有都是。

If there is room at the end (that is, if the number of characters to write is less than count), the buffer will be null-terminated.

该文档还明确暗示 vsnprintfbuffer==NULLcount==0 方面不符合 C99 标准的 (1.) 和 (2.) ;但文档的这些部分似乎是错误的:

if the number of characters to write is greater than count, these functions return -1 indicating that output has been truncated.

If buffer or format is NULL, or if count is less than or equal to zero, these functions invoke the invalid parameter handler


测试代码:

#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,即使输出是正数。

您提到的页面现在给出了答案:

Beginning with the UCRT in Visual Studio 2015 and Windows 10, vsnprintf is no longer identical to _vsnprintf. The vsnprintf function complies with the C99 standard; _vnsprintf is retained for backward compatibility with older Visual Studio code.

并且你的输出与_vsnprintf一致:

Both _vsnprintf and _vsnwprintf functions return the number of characters written if the number of characters to write is less than or equal to count; if the number of characters to write is greater than count, these functions return -1 indicating that output has been truncated.