Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 737
dippynark Avatar asked Mar 08 '17 00:03

dippynark


2 Answers

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.

like image 52
Schwern Avatar answered Sep 18 '22 13:09

Schwern


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

like image 43
Ricardo Branco Avatar answered Sep 19 '22 13:09

Ricardo Branco