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

时间:2016-01-25 15:35:15

标签: c++ c visual-studio printf standards

根据Microsoft's documentation for 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

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

  • #define _CRT_SECURE_NO_WARNINGS#include <stdio.h>之前执行,这是现代版本的Visual Studio RTL所必需的;
  • 如果count大于零,则buffer是指向(至少)count可写字符的指针;
  • 格式不是NULL,并且符合Microsoft's Format Specification syntax适用于特定版本的RTL;
  • count的值和要生成的字符数都足够小以适合int类型;

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

  1. 在上述假设下未产生未定义的行为(包括调用Microsoft's invalid parameter handler);
  2. buffer==NULLcount==0时返回要写入的长度(不包括终止空字符),从而允许在飞行前确定输出的长度;
  3. buffer!=NULLcount>0时始终使用终止空字符填充输出字符串,并且返回的结果为非负数,包括由于小count而导致的截断输出。
  4. 请注意以下comment:我愿意承认缺少restrict限定符仍然可以满足大多数符合标准的要求。

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

      

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

    文件中还明确暗示vsnprintfbuffer==NULLcount==0时{1}}不符合关于(1.)和(2.)的C99标准;但文档的这些部分似乎是错误的:

      

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

         

    如果bufferformatNULL,或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特别是缺少终止空字符,即使输出为正。

1 个答案:

答案 0 :(得分:3)

您刚才提到的页面给出了答案:

  

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

您的输出与_vsnprintf一致:

  

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