如何在 C++03 中用 sprintf 正确替换 sprintf_s?
How to properly replace sprintf_s by sprintf in C++03?
sprintf_s
是函数 sprintf
的 Microsoft 实现,他们修补了一个缺陷,添加了一个参数来获取函数被限制写入的边界值。
C++11
中引入了等效项:snprintf
。但在这里,我们谈论的是 C++03
语法。
签名:
count_char_written sprintf(char* string_out, const char* output_template, VARIADIC_ARGS);
// and
count_char_written sprintf_s(char* string_out, size_t buffer_max_size, const char* output_template, VARIADIC_ARGS);
功能上,sprintf_s
比sprintf
更高级,因为它避免了溢出。
但是 sprintf_s
仅限 Microsoft!
如果要将使用 sprintf_s
编写的 C++03
代码移植回 POSIX 兼容语法怎么办?
今天 snprintf
和 vsnprintf
应该随处可用,但 MSVC12 及更早版本的 Windows 除外。对您来说最简单的方法是在 Windows 上提供 snprintf
/vsnprintf
不可用的地方。
Windows 提供的功能 _vsnprintf_s
已经与 vsnprintf
类似,但在提供的缓冲区太小时会发生以下重要差异:
- 缓冲区内容取决于
vsnprintf
中不存在的附加 count
参数。要获得 vsnprintf
行为,您可以在此处传递 _TRUNCATE
。
返回 -1
而不是所需的字符数。这可以通过使用 _vscprintf
函数来解决,该函数只需要在之前调用 _vsnprintf_s
失败时调用。
此外,这些函数不支持 C99 中添加的格式说明符,例如 %zd
。这不容易解决,您将不得不避免使用它们。
代码如下:
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
int r = -1;
if (size != 0)
{
va_list args_copy;
va_copy(args_copy, args);
r = _vsnprintf_s(buf, size, _TRUNCATE, fmt, args_copy);
va_end(args_copy);
}
if (r == -1)
{
r = _vscprintf(fmt, args);
}
return r;
}
int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int r = vsnprintf(buf, size, fmt, args);
va_end(args);
return r;
}
注意:Windows 还提供了 _vsnprintf
,它看起来更适合此实现,但它不会终止生成的字符串。想用的话还是慎重吧。
sprintf_s
是函数 sprintf
的 Microsoft 实现,他们修补了一个缺陷,添加了一个参数来获取函数被限制写入的边界值。
C++11
中引入了等效项:snprintf
。但在这里,我们谈论的是 C++03
语法。
签名:
count_char_written sprintf(char* string_out, const char* output_template, VARIADIC_ARGS);
// and
count_char_written sprintf_s(char* string_out, size_t buffer_max_size, const char* output_template, VARIADIC_ARGS);
功能上,sprintf_s
比sprintf
更高级,因为它避免了溢出。
但是 sprintf_s
仅限 Microsoft!
如果要将使用 sprintf_s
编写的 C++03
代码移植回 POSIX 兼容语法怎么办?
今天 snprintf
和 vsnprintf
应该随处可用,但 MSVC12 及更早版本的 Windows 除外。对您来说最简单的方法是在 Windows 上提供 snprintf
/vsnprintf
不可用的地方。
Windows 提供的功能 _vsnprintf_s
已经与 vsnprintf
类似,但在提供的缓冲区太小时会发生以下重要差异:
- 缓冲区内容取决于
vsnprintf
中不存在的附加count
参数。要获得vsnprintf
行为,您可以在此处传递_TRUNCATE
。
返回 -1
而不是所需的字符数。这可以通过使用_vscprintf
函数来解决,该函数只需要在之前调用_vsnprintf_s
失败时调用。
此外,这些函数不支持 C99 中添加的格式说明符,例如 %zd
。这不容易解决,您将不得不避免使用它们。
代码如下:
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
int r = -1;
if (size != 0)
{
va_list args_copy;
va_copy(args_copy, args);
r = _vsnprintf_s(buf, size, _TRUNCATE, fmt, args_copy);
va_end(args_copy);
}
if (r == -1)
{
r = _vscprintf(fmt, args);
}
return r;
}
int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int r = vsnprintf(buf, size, fmt, args);
va_end(args);
return r;
}
注意:Windows 还提供了 _vsnprintf
,它看起来更适合此实现,但它不会终止生成的字符串。想用的话还是慎重吧。