NAME

snprintf(3) - safe sprintf

 


SYNOPSIS


#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);


 


DESCRIPTION

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-Level

MT-Safe - provided that the locale is only set by the main thread before starting any other threads.

 


EXAMPLES

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; }


 


BUGS

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.