Tuesday, January 18, 2011

Output with ostream and ios

In this section, we will look at various aspects of the iostream output class (ostream).
Note: All of the I/O functionality in this lesson lives in the std namespace. That means all I/O objects and functions either have to be prefixed with “std::”, or the “using namespace std;” statement has to be used.
The insertion operator
The insertion operator (<<) is used to put information into an output stream. C++ has predefined insertion operations for all of the built-in data types, and you've already seen how you can overload the insertion operator for your own classes.
In the lesson on streams, you saw that both istream and ostream were derived from a class called ios. One of the jobs of ios (and ios_base) is to control the formatting options for output.
Formatting
There are two ways to change the formatting options: flags, and manipulators. You can think of flags as boolean variables that can be turned on and off. Manipulators are objects placed in a stream that affect the way things are input and output.
To switch a flag on, use the setf() function, with the appropriate flag as a parameter. For example, by default, C++ does not print a + sign in front of positive numbers. However, by using the ios::showpos flag, we can change this behavior:
1cout.setf(ios::showpos); // turn on the ios::showpos flag
2cout << 27 << endl;
This results in the following output:
+27
It is possible to turn on multiple ios flags at once using the OR (|) operator:
1cout.setf(ios::showpos | ios::uppercase); // turn on the ios::showpos and ios::uppercase flag
2cout << 27 << endl;
To turn a flag off, use the unsetf() function:
1cout.setf(ios::showpos); // turn on the ios::showpos flag
2cout << 27 << endl;
3cout.unsetf(ios::showpos); // turn off the ios::showpos flag
4cout << 28 << endl;
This results in the following output:
+27
28
There’s one other bit of trickiness when using setf() that needs to be mentioned. Many flags belong to groups, called format groups. A format group is a group of flags that perform similar (sometimes mutually exclusive) formatting options. For example, a format group named “basefield” contains the flags “oct”, “dec”, and “hex”, which controls the base of integral values. By default, the “dec” flag is set. Consequently, if we do this:
1cout.setf(ios::hex); // try to turn on hex output
2cout << 27 << endl;
We get the following output:
27
It didn’t work! The reason why is because setf() only turns flags on — it isn’t smart enough to turn mutually exclusive flags off. Consequently, when we turned ios::hex on, ios::dec was still on, and ios::dec apparently takes precedence. There are two ways to get around this problem.
First, we can turn off ios::dec so that only ios::hex is set:
1cout.unsetf(ios::dec); // turn off decimal output
2cout.setf(ios::hex); // turn on hexadecimal output
3cout << 27 << endl;
Now we get output as expected:
1b
The second way is to use a different form of setf() that takes two parameters: the first parameter is the flag to set, and the second is the formatting group it belongs to. When using this form of setf(), all of the flags belonging to the group are turned off, and only the flag passed in is turned on. For example:
1// Turn on ios::hex as the only ios::basefield flag
2cout.setf(ios::hex, ios::basefield);
3cout << 27 << endl;
This also produces the expected output:
1b
Using setf() and unsetf() tends to be awkward, so C++ provides a second way to change the formatting options: manipulators. The nice thing about manipulators is that they are smart enough to turn on and off the appropriate flags. Here is an example of using some manipulators to change the base:
1cout << hex << 27 << endl; // print 27 in hex
2cout << 28 << endl; // we're still in hex
3cout << dec << 29 << endl; // back to decimal
This program produces the output:
1b
1c
29
In general, using manipulators is much easier than setting and unsetting flags. Many options are available via both flags and manipulators (such as changing the base), however, other options are only available via flags or via manipulators, so it’s important to know how to use both.
Useful formatters
Here is a list of some of the more useful flags, manipulators, and member functions. Flags live in the ios class, manipulators lives in the std namespace, and the member functions live in the ostream class.
Group Flag Meaning

boolalpha If set, booleans print “true” or “false”. If not set, booleans print 0 or 1
Manipulator Meaning
boolalpha Booleans print “true” or “false”
noboolalpha Booleans print 0 or 1 (default)
Example:
1cout << true << " " << false << endl;
2
3cout.setf(ios::boolalpha);
4cout << true << " " << false << endl;
5
6cout << noboolalpha << true << " " << false << endl;
7
8cout << boolalpha << true << " " << false << endl;
Result:
0 1
true false
0 1
true false
Group Flag Meaning

showpos If set, prefix positive numbers with a +
Manipulator Meaning
showpos Prefixes positive numbers with a +
noshowpos Doesn’t prefix positive numbers with a +
Example:
1cout << 5 << endl;
2
3cout.setf(ios::showpos);
4cout << 5 << endl;
5
6cout << noshowpos << 5 << endl;
7
8cout << showpos << 5 << endl;
Result:
5
+5
5
+5
Group Flag Meaning

uppercase If set, uses upper case letters
Manipulator Meaning
uppercase Uses upper case letters
nouppercase Uses lower case letters
Example:
1cout << 12345678.9 << endl;
2
3cout.setf(ios::uppercase);
4cout << 12345678.9 << endl;
5
6cout << nouppercase << 12345678.9<< endl;
7
8cout << uppercase << 12345678.9 << endl;
Result:
1.23457e+007
1.23457E+007
1.23457e+007
1.23457E+007
Group Flag Meaning
basefield dec Prints values in decimal (default)
basefield hex Prints values in hexadecimal
basefield oct Prints values in octal
basefield (none) Prints values according to leading characters of value
Manipulator Meaning
dec Prints values in decimal
hex Prints values in hexadecimal
oct Prints values in octal
Example:
01cout << 27 << endl;
02
03cout.setf(ios::dec, ios::basefield);
04cout << 27 << endl;
05
06cout.setf(ios::oct, ios::basefield);
07cout << 27 << endl;
08
09cout.setf(ios::hex, ios::basefield);
10cout << 27 << endl;
11
12cout << dec << 27 << endl;
13cout << oct << 27 << endl;
14cout << hex << 27 << endl;
Result:
27
27
33
1b
27
33
1b
By now, you should be able to see the relationship between setting formatting via flag and via manipulators. In future examples, we will use manipulators unless they are not available.
Precision, notation, and decimal points
Using manipulators (or flags), it is possible to change the precision and format with which floating point numbers are displayed. There are several formatting options that combine in somewhat complex ways, so we will take a closer look at this.
Group Flag Meaning
floatfield fixed Uses decimal notation for floating-point numbers
floatfield scientific Uses scientific notation for floating-point numbers
floatfield (none) Uses fixed for numbers with few digits, scientific otherwise
floatfield showpoint Always show a decimal point and trailing 0′s for floating-point values
Manipulator Meaning
fixed Use decimal notation for values
scientific Use scientific notation for values
showpoint Show a decimal point and trailing 0′s for floating-point values
noshowpoint Don’t show a decimal point and trailing 0′s for floating-point values
setprecision(int) Sets the precision of floating-point numbers (defined in iomanip.h)
Member function Meaning
precision() Returns the current precision of floating-point numbers
precision(int) Sets the precision of floating-point numbers and returns old precision
If fixed or scientific notation is used, precision determines how many decimal places in the fraction is displayed. Note that if the precision is less than the number of significant digits, the number will be rounded.
01cout << fixed << endl;
02cout << setprecision(3) << 123.456 << endl;
03cout << setprecision(4) << 123.456 << endl;
04cout << setprecision(5) << 123.456 << endl;
05cout << setprecision(6) << 123.456 << endl;
06cout << setprecision(7) << 123.456 << endl;
07
08cout << scientific << endl;
09cout << setprecision(3) << 123.456 << endl;
10cout << setprecision(4) << 123.456 << endl;
11cout << setprecision(5) << 123.456 << endl;
12cout << setprecision(6) << 123.456 << endl;
13cout << setprecision(7) << 123.456 << endl;
Produces the result:
123.456
123.4560
123.45600
123.456000
123.4560000

1.235e+002
1.2346e+002
1.23456e+002
1.234560e+002
1.2345600e+002
If neither fixed nor scientific are being used, precision determines how many significant digits should be displayed. Again, if the precision is less than the number of significant digits, the number will be rounded.
1cout << setprecision(3) << 123.456 << endl;
2cout << setprecision(4) << 123.456 << endl;
3cout << setprecision(5) << 123.456 << endl;
4cout << setprecision(6) << 123.456 << endl;
5cout << setprecision(7) << 123.456 << endl;
Produces the following result:
123
123.5
123.46
123.456
123.456
Using the showpoint manipulator or flag, you can make the stream write a decimal point and trailing zeros.
1cout << showpoint << endl;
2cout << setprecision(3) << 123.456 << endl;
3cout << setprecision(4) << 123.456 << endl;
4cout << setprecision(5) << 123.456 << endl;
5cout << setprecision(6) << 123.456 << endl;
6cout << setprecision(7) << 123.456 << endl;
Produces the following result:
123.
123.5
123.46
123.456
123.4560
Here’s a summary table with some more examples:
Option Precision 12345.0 0.12345
Normal 3 1.23e+004 0.123
4 1.235e+004 0.1235
5 12345 0.12345
6 12345 0.12345
Showpoint 3 1.23e+004 0.123
4 1.235e+004 0.1235
5 12345. 0.12345
6 12345.0 0.123450
Fixed 3 12345.000 0.123
4 12345.0000 0.1235
5 12345.00000 0.12345
6 12345.000000 0.123450
Scientific 3 1.235e+004 1.235e-001
4 1.2345e+004 1.2345e-001
5 1.23450e+004 1.23450e-001
6 1.234500e+004 1.234500e-001
Width, fill characters, and justification
Typically when you print numbers, the numbers are printed without any regard to the space around them. However, it is possible to left or right justify the printing of numbers. In order to do this, we have to first define a field width, which defines the number of output spaces a value will have. If the actual number printed is smaller than the field width, it will be left or right justified (as specified). If the actual number is larger than the field width, it will not be truncated — it will overflow the field.
Group Flag Meaning
adjustfield internal Left-justifies the sign of the number, and right-justifies the value
adjustfield left Left-justifies the sign and value
adjustfield right Right-justifies the sign and value (default)
Manipulator Meaning
internal Left-justifies the sign of the number, and right-justifies the value
left Left-justifies the sign and value
right Right-justifies the sign and value
setfill(char) Sets the parameter as the fill character (defined in iomanip.h)
setw(int) Sets the field width for input and output to the parameter (defined in iomanip.h)
Member function Meaning
fill() Returns the current fill character
fill(char) Sets the fill character and returns the old fill character
width() Returns the current field width
width(int) Sets the current field width and returns old field width
In order to use any of these formatters, we first have to set a field width. This can be done via the width(int) member function, or the setw() manipulator. Note that right justification is the default.
1cout << -12345 << endl; // print default value with no field width
2cout << setw(10) << -12345 << endl; // print default with field width
3cout << setw(10) << left << -12345 << endl; // print left justified
4cout << setw(10) << right << -12345 << endl; // print right justified
5cout << setw(10) << internal << -12345 << endl; // print internally justified
This produces the result:
-12345
    -12345
-12345
    -12345
-    12345
One thing to note is that setw() and width() only affect the next output statement. They are not persistent like some other flags/manipulators.
Now, let’s set a fill character and do the same example:
1cout.fill('*');
2cout << -12345 << endl; // print default value with no field width
3cout << setw(10) << -12345 << endl; // print default with field width
4cout << setw(10) << left << -12345 << endl; // print left justified
5cout << setw(10) << right << -12345 << endl; // print right justified
6cout << setw(10) << internal << -12345 << endl; // print internally justified
This produces the output:
-12345
****-12345
-12345****
****-12345
-****12345
Note that all the blank spaces in the field have been filled up with the fill character.
The ostream class and iostream library contain other output functions, flags, and manipulators that may be useful, depending on what you need to do. As with the istream class, those topics are really more suited for a tutorial or book focusing on the standard library (such as the excellent “The C++ Standard Template Library” by Nicolai M. Josuttis).

No comments: