从什么版本的Visual Studio开始vsnprintf大部分都符合标准?

fgr*_*ieu 14 c c++ standards printf visual-studio

根据微软的文档vsnprintf,该功能至少是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
Run Code Online (Sandbox Code Playgroud)

我问:Visual Studio的哪个版本是vsnprintfx86和x64的捆绑C(++)RTL的实现,符合C99标准(ISO/IEC 9899:1999),假设

  • #define _CRT_SECURE_NO_WARNINGS以前执行#include <stdio.h>,这是现代版本的Visual Studio RTL所必需的;
  • 如果count大于零,则buffer指向(至少)count可写字符;
  • 格式不NULL符合Microsoft的格式规范语法,适用于特定版本的RTL;
  • 的值count和字符,以产生均足够小以适合类型的数目int;

并且我们希望符合(包括标称输入的基本功能)这些要求(由标准的规范暗示snprintf,vsnprintf引用):

  1. 在上述假设下不产生未定义的行为(包括调用Microsoft的无效参数处理程序);
  2. buffer==NULL和时返回要写入的长度(不包括终止空字符)count==0,从而允许在飞行前确定输出的长度;
  3. buffer!=NULL和时,总是用终止空字符填充输出字符串,count>0并且返回的结果是非负的,包括由于小的截断输出count.

请注意以下评论:我愿意承认缺乏restrict限定符仍然在大多数符合标准的范围内.


文档中的符合性与(3.); 据我所知,与Visual Studio Community 2015捆绑在一起的实现很好,但不是全部.

如果最后有空间(即,如果要写入的字符数小于count),则缓冲区将以空值终止.

该文件还明确暗示,vsnprintf与(1)和(2.)何时buffer==NULL和时无关,不符合C99标准count==0; 但文档的这些部分似乎是错误的:

如果要写入的字符数大于count,则这些函数返回-1表示输出已被截断.

如果buffer或者formatNULL,或者如果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;
}
Run Code Online (Sandbox Code Playgroud)

在我安装的Visual Studio社区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"
Run Code Online (Sandbox Code Playgroud)

并在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"
Run Code Online (Sandbox Code Playgroud)

请注意count==3,即使输出为正,也缺少终止空字符.

Mic*_*bez 5

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

从 Visual Studio 2015 和 Windows 10 中的 UCRT 开始,vsnprintf 不再与 _vsnprintf 相同。vsnprintf函数符合C99标准;保留 _vnsprintf 是为了向后兼容旧版 Visual Studio 代码。

并且您的输出与_vsnprintf一致:

如果要写入的字符数小于或等于 count,则 _vsnprintf 和 _vsnwprintf 函数都返回写入的字符数;如果要写入的字符数大于 count,这些函数将返回 -1,表示输出已被截断。