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-1st 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.


SEE ALSO

printf(3), sprintf(3), vsprintf(3)


AUTHOR

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>