Writing to stdout and stderr
In this recipe, we'll learn how to print text to both stdout and stderr in a C program. In the two previous recipes, we learned what stdout and stderr are, why they exist, and how to redirect them. Now, it's our turn to write correct programs that output error messages on standard error, and regular messages on standard output.
How to do it…
Follow these steps to learn how to write output to both stdout and stderr in a C program:
- Write the following code in a file called
output.c
and save it. In this program, we will write output using three different functions:printf()
,fprintf()
, anddprintf()
. Withfprintf()
, we can specify a file stream such as stdout or stderr, while withdprintf()
, we can specify the file descriptor (1 for stdout and 2 for stderr, just as we have seen previously):#define _POSIX_C_SOURCE 200809L #include <stdio.h> int main(void) { Â Â Â printf("A regular message on stdout\n"); Â Â Â /* Using streams with fprintf() */ Â Â Â fprintf(stdout, "Also a regular message on " Â Â Â Â Â "stdout\n"); Â Â Â fprintf(stderr, "An error message on stderr\n"); Â Â Â /* Using file descriptors with dprintf(). Â Â Â Â * This requires _POSIX_C_SOURCE 200809L Â Â Â Â * (man 3 dprintf)*/ Â Â Â dprintf(1, "A regular message, printed to " Â Â Â Â Â Â Â Â "fd 1\n"); Â Â Â dprintf(2, "An error message, printed to " Â Â Â Â Â Â Â Â Â "fd 2\n"); Â Â Â return 0; }
- Compile the program:
$> gcc output.c -o output
- Run the program like you usually would:
$> ./output A regular message on stdout Also a regular message on stdout An error message on stderr A regular message, printed to fd 1 An error message, printed to fd 2
- To prove that the regular messages are printed to stdout, we can send the error messages to
/dev/null
, a black hole in the Linux system. Doing this will only display the messages printed to stdout:$> ./output 2> /dev/null A regular message on stdout Also a regular message on stdout A regular message, printed to fd 1
- Now, we will do the reverse; we will send the messages printed to stdout to
/dev/null
, showing only the error messages that are printed to stderr:$> ./output > /dev/null An error message on stderr An error message, printed to fd 2
- Finally, let's send all messages, from both stdout and stderr, to
/dev/null
. This will display nothing:$> ./output &> /dev/null
How it works…
The first example, where we used printf()
, doesn't contain anything new or unique. All output printed with the regular printf()
function is printed to stdout.
Then, we saw some new examples, including the two lines where we use fprintf()
. That function, fprintf()
, allows us to specify a file stream to print the text to. We will cover what a stream is later on in this book. But in short, a file stream is what we usually open when we want to read or write to a file in C using the standard library. And remember, everything is either a file or a process in Linux. When a program opens in Linux, three file streams are automatically opened—stdin, stdout, and stderr (assuming the program has included stdio.h
).
Then, we looked at some examples of using dprintf()
. This function allows us to specify a file descriptor to print to. We covered file descriptors in the previous recipes of this chapter, but we will discuss them in more depth later in this book. Three file descriptors are always open—0 (stdin), 1 (stdout), and 2 (stderr)—in every program we write on Linux. Here, we printed the regular message to file descriptor (fd for short) 1, and the error message to file descriptor 2.
To be correct in our code, we need to include the very first line (the #define
line) for the sake of dprintf()
. We can read all about it in the manual page (man 3 dprintf
), under Feature Test Macro Requirements. The macro we define, _POSIX_C_SOURCE
, is for POSIX standards and compatibility. We will cover this in more depth later in this book.
When we tested the program, we verified that the regular messages got printed to standard output by redirecting the error messages to a file called /dev/null
, showing only the messages printed to standard output. Then, we did the reverse to verify that the error messages got printed to standard error.
The special file, /dev/null
, acts as a black hole in Linux and other Unix systems. Everything we send to that file simply disappears. Try it out with ls / &> /dev/null
, for example. No output will be displayed since everything is redirected to the black hole.
There's more…
I mentioned that three file streams are opened in a program, assuming it includes stdio.h
, as well as three file descriptors. These three file descriptors are always opened, even if stdio.h
is not included. If we were to include unistd.h
, we could also use macro names for the three file descriptors.
The following table shows these file descriptors, their macro names, and file streams, which are handy for future reference: