snprintf和Visual Studio 2010

我不幸被一个项目的VS 2010卡住了,并且注意到下面的代码仍然不能使用不符合标准的编译器来编译:

#include <stdio.h> #include <stdlib.h> int main (void) { char buffer[512]; snprintf(buffer, sizeof(buffer), "SomeString"); return 0; } 

(编译失败,错误:C3861:'snprintf':标识符未find)

我记得在VS2005的情况下,我很震惊地看到它仍然没有被修复。

有谁知道微软是否有计划将其标准C库移植到2010年?

简短的故事:微软终于在Visual Studio 2015中实现了snprintf。在早期的版本中,你可以如下模拟它。


长版本:

以下是snprintf的预期行为:

 int snprintf( char* buffer, std::size_t buf_size, const char* format, ... ); 

最多写入buf_size - 1字符到缓冲区。 生成的string将以空字符结尾,除非buf_size为零。 如果buf_size为零,则不会写入任何内容,并且buffer可能是空指针。 返回值是假定无限buf_size将被写入的字符数,不包括终止空字符。

Visual Studio 2015之前的版本没有一致的实现。 有一些非标准的扩展,例如_snprintf() (它不会在溢出时写null-terminator)和_snprintf_s() (它可以实现空终止,但在溢出时返回-1,而不是返回的字符数已被写入)。

build议的回退VS 2005及以上:

 #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf c99_snprintf #define vsnprintf c99_vsnprintf __inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { int count = -1; if (size != 0) count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); if (count == -1) count = _vscprintf(format, ap); return count; } __inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) { int count; va_list ap; va_start(ap, format); count = c99_vsnprintf(outBuf, size, format, ap); va_end(ap); return count; } #endif 

snprintf不是C89的一部分。 这只是在C99标准。 微软没有支持C99的计划 。

(但它也是C ++ 0x …的标准)

有关解决方法,请参阅下面的其他答案。

如果你不需要返回值,你也可以将snprintf定义为_snprintf_s

 #define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__) 

我相信Windows相当于sprintf_s

snprintf()vsnprintf()另一个安全replace是由ffmpeg提供的。 你可以在这里查看源代码 (build议)。

我试过@Valentin Milea的代码,但我有访问冲突错误。 唯一对我有效的是Insane Coding的实现: http : //asprintf.insanecoding.org/

具体来说,我正在使用VC ++ 2008遗留代码。 从Insane Coding的实现(可以从上面的链接下载),我使用了三个文件: asprintf.casprintf.hvasprintf-msvc.c 。 其他文件是用于其他版本的MSVC。

[编辑]为了完整,其内容如下:

asprintf.h:

 #ifndef INSANE_ASPRINTF_H #define INSANE_ASPRINTF_H #ifndef __cplusplus #include <stdarg.h> #else #include <cstdarg> extern "C" { #endif #define insane_free(ptr) { free(ptr); ptr = 0; } int vasprintf(char **strp, const char *fmt, va_list ap); int asprintf(char **strp, const char *fmt, ...); #ifdef __cplusplus } #endif #endif 

asprintf.c:

 #include "asprintf.h" int asprintf(char **strp, const char *fmt, ...) { int r; va_list ap; va_start(ap, fmt); r = vasprintf(strp, fmt, ap); va_end(ap); return(r); } 

vasprintf-msvc.c:

 #include <stdio.h> #include <stdlib.h> #include <limits.h> #include "asprintf.h" int vasprintf(char **strp, const char *fmt, va_list ap) { int r = -1, size = _vscprintf(fmt, ap); if ((size >= 0) && (size < INT_MAX)) { *strp = (char *)malloc(size+1); //+1 for null if (*strp) { r = vsnprintf(*strp, size+1, fmt, ap); //+1 for null if ((r < 0) || (r > size)) { insane_free(*strp); r = -1; } } } else { *strp = 0; } return(r); } 

用法(由Insane编码提供的test.c一部分):

 #include <stdio.h> #include <stdlib.h> #include "asprintf.h" int main() { char *s; if (asprintf(&s, "Hello, %d in hex padded to 8 digits is: %08x\n", 15, 15) != -1) { puts(s); insane_free(s); } }