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:
count
argument which does not exist in vsnprintf
. To get vsnprintf
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.