Why would I need use fflush on stdout before writing to stderr?
Asked Answered
T

2

15

I am reading 'UNIX Network Programming: The Sockets Networking API' and in the example code they have an error handling function which contains the following lines:

fflush(stdout);     /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);

Where buf contains the error description. I don't understand why fflush is used on stdout on the first line and why the comment explains the reason for its use.

Tridactyl answered 8/3, 2017 at 0:8 Comment(0)
L
26

This is because of buffering. Stdout and stderr are usually buffered differently. Stdout is usually line buffered, meaning it will not display output until it sees a newline. Stderr is usually unbuffered and will print immediately, the thinking is you should see error messages pronto.

But they both go to the same place, the terminal. This is what it means by /* in case stdout and stderr are the same */. They usually are. But because they're buffered differently this can lead to them being displayed out of order.

Consider this code. Note the lack of a newlines.

#include <stdio.h>

int main() {
    fprintf(stdout, "This is to stdout. ");
    fprintf(stderr, "This is to stderr. ");
    fprintf(stdout, "This is also to stdout. ");
}

You'd expect the output to be:

This is to stdout. This is to stderr. This is also to stdout.

But it isn't. It's out of order.

$ ./test
This is to stderr. This is to stdout. This is also to stdout.

The output to stderr is displayed immediately, it is unbuffered. While stdout has to wait until the stdout buffer is flushed by a newline. There is no newline, so it is flushed when the program exits.

By flushing stdout before you use stderr you ensure that the output comes in the right order regardless of buffering.

#include <stdio.h>
#include <unistd.h>

int main() {
    fprintf(stdout, "This is to stdout. ");
    fflush(stdout);
    fprintf(stderr, "This is to stderr. ");
    fprintf(stdout, "This is also to stdout. ");
}

$ ./test
This is to stdout. This is to stderr. This is also to stdout. 

This ensures that error messages come out in the right order along with normal messages. This avoids confusion about what error message applies to what part of the program.

Luckett answered 8/3, 2017 at 0:30 Comment(3)
Your second example is wrong; This is also to stdout. and This is to stdout. should be switched.Virile
If stderr was uncharacteristically line buffered, similar problems would occur that are not fixed by this answer. Pedantically, flush the other one before writing. Or use good etiquette and [flush once you are done]Randolph
@Qix Thanks. I'd originally mixed up the filehandles in the code.Luckett
E
2

If stdout and stderr point to the same file, you have to be sure that whatever is in the stdout buffer is written first.

Excusatory answered 8/3, 2017 at 0:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.