Standard Streams and I/O Redirection


Every C++ program has access to three preconnected input and output communication channels called standard streams. The three input/output (I/O) connections are:

The stream objects cin, cout, cerr, and clog are declared in the header file <iostream>. The code translation unit in which they are defined ensures that they are constructed automatically before program execution begins and they remain in existence for the entire execution of a program.

A C++ program can also open additional input or output streams, including file streams associated with named files or string streams that use a C++ string as the source of input or the destination of output.

I/O Redirection

While the standard streams have default associations, they can be redirected. For example, standard input can be redirected to read from a file or the output of another program, while standard output or standard error can be redirected to write to a file or to send its output as input to another program.

You may need to do some redirection for some of your programs. Redirection can be from standard input, standard output, or standard error. The redirection of I/O is documented in the Unix man pages under the command bash because it is performed by the Unix command line shell.

Sometimes you may be given a data file as input to test your program. You use it by running your program (with its command line options) and then using the less-than symbol (<) followed by a filename that contains the data to send to the running program.

For example, to redirect the data in the file named data1 into the program prog1:

./prog1 < data1

Sometimes, rather than printing on the screen, you will want to save your output in a file for later use. To do this, you redirect standard output to a file using the greater-than symbol (>).

The operating system will automatically create the file for you if it does not already exist. Caution: if the specified output file already exists, running this command will erase the contents of the file and fill it with the new output.

To save the output of the program prog2 into a file called out2:

./prog2 > out2

To append data to the end of a file, you would do the following:

./prog2 >> out2

You may also redirect the standard output and the standard error (which includes error messages from g++ and make) to a file.

(You may be asking what is standard error? It's a separate output stream that is used, by convention, by programs when they are printing error messages. In C++, the object cerr can be used to write to standard error in a fashion similar to cout.)

One very handy use is to redirect the errors you get from the C++ compiler to a file. Then you can print it out.

g++ -Wall -Werror -std=c++11 -o prog1 prog1.cpp >& prog1.err
    
make >& errors.txt

If you want to append to the end of the output file, you would again use a double greater-than symbol like this:

g++ -Wall -Werror -std=c++11 -o prog1 prog1.cpp >>& prog1.err
        
make >>& errors.txt

Rather than redirecting the output of a command into a file, you might want to redirect into the input of another program. To do this, you use the pipe symbol. For example, if you want to display the output from the program prog1 screen by screen, you could pipe it to the more command like this:

./prog1 | more

Note that the standard input for prog1 is not altered and will be the keyboard. The standard output of the more command is also not altered and will print to the screen.

Error messages from the make can also be redirected to the more command:

make |& more

It's generally best practice to try to fix syntax errors in the order that they are printed because a single mistake in your C++ code can potentially cascade through an entire source file, producing multiple error messages. Redirecting the error output from the make command to a file or the more can make it easier to see the the earliest error messages when you have a very large number of syntax errors.

You can also mix redirection. For example, if you want your program to take data from a file and put the output into another file, you can do the following:

./prog6 < datafile > output

Or you might even want to do something like this:

./prog6 < datafile | sort > output