May printf (or fprintf or dprintf) return ("successfully") less (but nonnegative) than the number of "all bytes"?

Question

The manual says that

Upon successful return, these functions [printf, dprintf etc.] return the number of characters printed.

The manual does not mention whethet may this number less (but yet nonnegative) than the length of the "final" (substitutions and formattings done) string. Nor mentions that how to check whether (or achieve that) the string was completely written.

The dprintf function operates on file descriptor. Similarily to the write function, for which the manual does mention that

On success, the number of bytes written is returned (zero indicates nothing was written). It is not an error if this number is smaller than the number of bytes requested;

So if I want to write a string completely then I have to enclose the n = write() in a while-loop. Should I have to do the same in case of dprintf or printf?


Show source
| C   | printf   | return-value   2016-11-17 17:11 3 Answers

Answers ( 3 )

  1. 2016-11-17 17:11

    My understanding of the documentation is that dprintf would either fail or output all the output. But I agree that it is some gray area (and I might not understand well); I'm guessing that a partial output is some kind of failure (so returns a negative size).

    Here is the implementation of musl-libc:

    In stdio/dprintf.c the dprintf function just calls vdprintf

    But in stdio/vdprintf.c you just have:

    static size_t wrap_write(FILE *f, const unsigned char *buf, size_t len)
    {
        return __stdio_write(f, buf, len);
    }
    
    int vdprintf(int fd, const char *restrict fmt, va_list ap)
    {
        FILE f = {
            .fd = fd, .lbf = EOF, .write = wrap_write,
            .buf = (void *)fmt, .buf_size = 0,
            .lock = -1
        };
        return vfprintf(&f, fmt, ap);
    }
    

    So dprintf is returning a size like vfprintf (and fprintf....) does.

    However, if you really are concerned, you'll better use snprintf or asprintf to output into some memory buffer, and explicitly use write(2) on that buffer.

    Look into stdio/__stdio_write.c the implementation of __stdio_write (it uses writev(2) with a vector of two data chunks in a loop).

    In other words, I would often not really care; but if you really need to be sure that every byte has been written as you expect it (for example if the file descriptor is some HTTP socket), I would suggest to buffer explicitly (e.g. by calling snprintf and/or asprintf) yourself, then use your explicit write(2).

    PS. You might check yourself the source code of your particular C standard library providing dprintf; for GNU glibc see notably libio/iovdprintf.c

  2. 2016-11-17 18:11

    With stdio, returning the number of partially written bytes doesn't make much sense because stdio functions work with a (more or less) global buffer whose state is unknown to you and gets dragged in from previous calls.

    If stdio functions allowed you to work with that, the error return values would need to be more complex as they would not only need to communicate how many characters were or were not outputted, but also whether the failure was before your last input somewhere in the buffer, or in the middle of your last input and if so, how much of the last input got buffered.

    The d-functions could theoretically give you the number of partially written characters easy, but POSIX specifies that they should mirror the stdio functions and so they only give you a further unspecified negative value on error.

    If you need more control, you can use the lower level functions.

  3. 2016-11-17 18:11

    Concerning printf(), it is quite clear.

    The printf function returns the number of characters transmitted, or a negative value if an output or encoding error occurred. C11dr §7.21.6.3 3

    A negative value is returned if an error occurred. In that case 0 or more characters may have printed. The count is unknowable via the standard library.

    If the value return is not negative, that is the number sent to stdout.

    Since stdout is often buffered, that may not be the number received at the output device on the conclusion of printf(). Follow printf() with a fflush(stdout)

    int r1 = printf(....);
    int r2 = fflush(stdout);
    if (r1 < 0 || r2 != 0) Handle_Failure();
    

    For finest control, "print" to a buffer and use putchar() or various non-standard functions.

◀ Go back