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) of that doesn't suffer from buffer overruns.
int snprintf(char *str, size_t size, const char *format, ...)
Writes output to the string 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 characters to produce. The trailing nul
character is counted
towards this limit, so you must allocate at least size
characters for
str
.
If size
is zero, nothing is written and str
may be null
. Otherwise,
output characters beyond the n-1
st are discarded rather than being
written to str
, and a nul
character is written at the end of the
characters actually written to str
. If copying takes place between
objects that overlap, the behaviour is undefined.
On success, returns the number of characters that would have been written
had size
been sufficiently large, not counting the terminating nul
character. Thus, the nul
-terminated output has been completely written if
and only if the return value is nonnegative 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 characters
that would have been written had size
been sufficiently large (not
counting the terminating nul
character) 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 multibyte
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-2010 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>