Oh, I could have fun with the term “standard error device.” It could be any PCs running Windows 8. [rimshot] See? Tech humor! It’s nerdy, but that’s not the point of the standard error device with regards to C programming.
In C, as well as other programming languages, three standard I/O devices are available:
stdin
for standard input
stdout
for standard output
stderr
for error message output
The stdin
and stdout
devices are traditionally mapped to the keyboard and screen, respectively. In the olden days, these devices were a teletype. Anyway, input and output from these devices can be redirected. Input can flow from a file, for example, and output can be sent to a file or to another program, where it becomes standard input.
The stderr
device cannot be redirected. It’s always mapped to the same gizmo, which on modern computers is the terminal window. This device generates error messages or other text a programmer wants displayed and not sent elsewhere.
When you use any of C standard I/O library functions, they default to stdin
and stdout
for input and output:
#include <stdio.h> int main() { printf("Here is Line 1\n"); printf("Here is Line 2\n"); printf("Here is Line 3\n"); return(0); }
This code generates three lines of text. The printf() statement uses the stdout
device by default. Here’s the sample run:
Here is Line 1
Here is Line 2
Here is Line 3
This code is identical to the following:
#include <stdio.h> int main() { fprintf(stdout,"Here is Line 1\n"); fprintf(stdout,"Here is Line 2\n"); fprintf(stdout,"Here is Line 3\n"); return(0); }
In this example, the fprintf() function replaces printf(). It requires a stream argument before the format string, which can be the handle of an open file or one of the standard I/O devices. In C, stdout
is accepted as a stream argument, always open for every program you run, as are stdin
and stderr
. So in this example, the strings are sent to the “file” stdout
. The code’s output is the same.
In the next example, I changed the second fprintf() statement to use the stderr
output device instead of stdout
:
#include <stdio.h> int main() { fprintf(stdout,"Here is Line 1\n"); fprintf(stderr,"Here is Line 2\n"); fprintf(stdout,"Here is Line 3\n"); return(0); }
Again, the output is the same, but unlike stdout
, stderr
output cannot be redirected to another device. When I run the code in a terminal window and redirect the output elsewhere, I see only the text generated by the second fprintf() statement:
$ ./a.out > /dev/null
Here is Line 2
Above, the program (named a.out
) sent output the /dev/null
device, which is a “door to nowhere” in the Unix operating system. (In Windows, use > nul
.) The first and third fprintf() statement’s output meanders off in to the null
device, but because the second fprintf() statement sends it output to stderr
, it shows up in the terminal window.
In my code, I use the stderr
device to output error messages. Especially for programs I write where I know the output is immediately fed into another program, it’s important that I see those error messages directly. Output to stderr
guarantees that they show up, but the output isn’t without its quirks.
Because I/O in C is buffered, it’s common that an error message sent to stderr
appears out of sequence with other text sent to standard output. I tried to replicate this peculiarity with a sample program, but it takes too much code to make it work consistently. Still, it’s possible for an error message to show up earlier than other text sent to (buffered) standard output. That weird sequencing bugged me, but it’s something you must understand when you use stderr
to generate error output.
“Because I/O in C is buffered, it’s common that an error message sent to stderr appears out of sequence with other text sent to standard output.”
Would fflush(stderr) immediately after fix this problem?
The way I see the problem, you would use
fflush(stdout)
before using any statements that direct output tostderr
. The problem I’ve seen is that the error message appears in the midst of standard output text, which is what makes it difficult to spot. I see this only in longer code that does a lot of processing. That’s when I believe the buffering gets all tangled. But you’re correct, flushing either stream would generate the immediate output. In my example, you’d want to flushstdout
first.By the way, as a reader pointed out on LinkedIn, you can redirect output sent to the standard error device. You must specify the value 2 before the redirection symbol,
>
, as in./a.out 2> error.log
I’m aware of this output redirection override. In fact, the default for output redirection is really
1>
, though the 1 is optional. Plus – and this is news to me – this type of output redirection for thestderr
device also works in Windows! I learn something new every day.