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.c
, asprintf.h
和vasprintf-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); } }