snprintf(3) - safe sprintf
#include <slack/std.h>
#ifndef HAVE_SNPRINTF
#include <slack/snprintf.h>
#endif
int snprintf(char *str, size_t size, const char *format, ...);
int vsnprintf(char *str, size_t size, const char *format, va_list args);
Safe version of sprintf(3) that doesn't suffer from buffer overruns.
int snprintf(char *str, size_t size, const char *format, ...)
Writes output to the buffer, str
, under control of the format string format
, that specifies how subsequent arguments are converted for output. It is similar to sprintf(3), except that size
specifies the maximum number of bytes to produce. The trailing nul
byte is counted towards this limit, so you must allocate at least size
bytes for str
.
If size
is zero, nothing is written, and str
may be null
. Otherwise, output bytes beyond the n-1
st are discarded rather than being written to str
, and a nul
byte is written at the end of the bytes actually written to str
. If copying takes place between objects that overlap, the behaviour is undefined.
On success, returns the number of bytes that would have been written had size
been sufficiently large, not counting the terminating nul
byte. Thus, the nul
-terminated output has been completely written if and only if the return value is non-negative and less than size
. On error, returns -1
(i.e. encoding error).
Note that if your system already has snprintf(3), but this implementation was installed anyway, it's because the system implementation has a broken return value. Some older implementations (e.g. glibc-2.0) return -1
when the string is truncated rather than returning the number of bytes that would have been written had size
been sufficiently large (not counting the terminating nul
byte) as required by ISO/IEC 9899:1999(E).
int vsnprintf(char *str, size_t size, const char *format, va_list args)
Equivalent to snprintf(3) with the variable argument list specified directly as for vsprintf(3).
MT-Safe - provided that the locale is only set by the main thread before starting any other threads.
How long is a piece of string?
#include <slack/std.h>
#ifndef HAVE_SNPRINTF
#include <slack/snprintf.h>
#endif
int main(int ac, char **av)
{
char *str;
int len;
len = snprintf(NULL, 0, "%s %d", *av, ac);
printf("this string has length %d\n", len);
if (!(str = malloc((len + 1) * sizeof(char))))
return EXIT_FAILURE;
len = snprintf(str, len + 1, "%s %d", *av, ac);
printf("%s %d\n", str, len);
free(str);
return EXIT_SUCCESS;
}
Check if truncation occurred:
#include <slack/std.h>
#ifndef HAVE_SNPRINTF
#include <slack/snprintf.h>
#endif
int main()
{
char str[16];
int len;
len = snprintf(str, 16, "%s %d", "hello world", 1000);
printf("%s\n", str);
if (len >= 16)
printf("length truncated (from %d)\n", len);
return EXIT_SUCCESS;
}
Allocate memory only when needed to prevent truncation:
#include <slack/std.h>
#ifndef HAVE_SNPRINTF
#include <slack/snprintf.h>
#endif
int main(int ac, char **av)
{
char buf[16];
char *str = buf;
char *extra = NULL;
int len;
if (!av[1])
return EXIT_FAILURE;
if ((len = snprintf(buf, 16, "%s", av[1])) >= 16)
if (extra = malloc((len + 1) * sizeof(char)))
snprintf(str = extra, len + 1, "%s", av[1]);
printf("%s\n", str);
if (extra)
free(extra);
return EXIT_SUCCESS;
}
The format control string, format
, should be interpreted as a multi-byte character sequence but it is not. Apart from that, these functions comply with the ISO C 89 formatting requirements specified for the fprintf(3) function (section 7.9.6.1).
Even though snprintf(3) is an ISO C 99 function (section 7.19.6.5), this implementation does not support the new ISO C 99 formatting conversions or length modifiers (i.e. %hh[diouxXn]
, %ll[diouxXn]
, %j[diouxXn]
, %z[diouxXn]
, %t[diouxXn]
, %ls
, %lc
and %[aAF]
). The main reason is that the local system's sprintf(3) function is used to perform floating point formatting. If the local system can support %[aA]
, then you must have C99 already, and so you must also have snprintf(3) already.
If snprintf(3) or vsnprintf(3) require more than 512
bytes of space in which to format a floating point number, but fail to allocate the required space, the floating point number will not be formatted at all, and processing will continue. There is no indication to the client that an error occurred. The chances of this happening are remote. It would take a field width or precision greater than the available memory to trigger this bug. Since there are only 15
significant digits in a double and only 18
significant digits in an 80
bit long double (33
significant digits in a 128
bit long double), a precision larger than 15
/18
/33
serves no purpose, and a field width larger than the useful output serves no purpose.
printf(3), sprintf(3), vsprintf(3)
2002-2023 raf <raf@raf.org>, 1998 Andrew Tridgell <tridge@samba.org>, 1998 Michael Elkins <me@cs.hmc.edu>, 1998 Thomas Roessler <roessler@guug.de>, 1996-1997 Brandon Long <blong@fiction.net>, 1995 Patrick Powell <papowell@astart.com>