问题描述
sprintf_s
是函数 sprintf
的微软实现,他们修补了一个缺陷,添加了一个参数来获取函数被限制写入的边界值.>
C++11
中引入了一个等价物:snprintf
.但在这里,我们谈论的是 C++03
语法.
签名:
count_char_written sprintf(char* string_out, const char* output_template, VARIADIC_ARGS);//和count_char_written sprintf_s(char* string_out, size_t buffer_max_size, const char* output_template, VARIADIC_ARGS);
Functionnaly,sprintf_s
比 sprintf
更先进,因为它避免了溢出.但是 sprintf_s
只是微软的!
如果您想将用 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;如果(大小!= 0){va_list args_copy;va_copy(args_copy, args);r = _vsnprintf_s(buf, size, _TRUNCATE, fmt, args_copy);va_end(args_copy);}如果 (r == -1){r = _vscprintf(fmt, args);}返回 r;}int snprintf(char *buf, size_t size, const char *fmt, ...){va_list 参数;va_start(args, fmt);int r = vsnprintf(buf, size, fmt, args);va_end(参数);返回 r;}
注意:Windows 还提供了 _vsnprintf
,它看起来更适合此实现,但它不会终止生成的字符串.如果你想使用它,你应该小心.
sprintf_s
is a Microsoft implementation of the function sprintf
where they patched a flaw, adding an argument to take a boundary value where the function is limited to write.
An equivalent was introduced in C++11
: snprintf
. But here, we are talking of C++03
syntax.
Signatures:
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);
Functionnaly, sprintf_s
is more advanced than sprintf
, because it avoids overflows.But sprintf_s
is Microsoft only!
What to do if you want to port back a C++03
code written with sprintf_s
to POSIX compatible syntax?
Today both snprintf
and vsnprintf
should be available everywhere with the exception of Windows with MSVC12 and older. The simplest way for you is to provide snprintf
/vsnprintf
on Windows where it is not available.
Windows provides function _vsnprintf_s
which is already similar to vsnprintf
, but has following important differences with regards to what happens when provided buffer is too small:
- Buffer content depends on the additional
count
argument which does not exist invsnprintf
. To getvsnprintf
behavior you can pass_TRUNCATE
here. -1
is returned instead of number of characters required. This can be fixed by using_vscprintf
function which only needs to be called if previous call to_vsnprintf_s
has failed.
Additionally those functions do not support format specifiers added in C99 such as %zd
. This cannot be easily resolved, you will have to avoid using them.
Code below:
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;
}
Note: Windows also provides _vsnprintf
which looks better suited for this implementation, but it does not terminate the resulting string. If you want to use it, you should be careful.
这篇关于如何在 C++03 中用 sprintf 正确替换 sprintf_s?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!