The formatting functions in iostreams can be somewhat confusing at first because there’s often more than one way to control the formatting: through both member functions and manipulators. To further confuse things, a generic member function sets state flags to control formatting, such as left or right justification, to use uppercase letters for hex notation, to always use a decimal point for floating-point values, and so on. On the other hand, separate member functions set and read values for the fill character, the field width, and the precision.
In an attempt to clarify all this, we’ll first examine the internal formatting data of an iostream , along with the member functions that can modify that data. (Everything can be controlled through the member functions, if desired.) We’ll cover the manipulators separately.
Format flags
The class ios contains data members to store all the formatting information pertaining to a stream. Some of this data has a range of values and is stored in variables: the floating-point precision, the output field width, and the character used to pad the output (normally a space). The rest of the formatting is determined by flags, which are usually combined to save space and are referred to collectively as the format flags. You can find out the value of the format flags with the ios::flags( ) member function, which takes no arguments and returns an object of type fmtflags (usually a synonym for long) that contains the current format flags. All the rest of the functions make changes to the format flags and return the previous value of the format flags.
fmtflags ios::flags(fmtflags newflags);
fmtflags ios::setf(fmtflags ored_flag);
fmtflags ios::unsetf(fmtflags clear_flag);
fmtflags ios::setf(fmtflags bits, fmtflags field);
The first function forces all the flags to change, which you do sometimes. More often, you change one flag at a time using the remaining three functions.
The use of setf( ) can seem somewhat confusing. To know which overloaded version to use, you must know what type of flag you’re changing. There are two types of flags: those that are simply on or off, and those that work in a group with other flags. The on/off flags are the simplest to understand because you turn them on with setf(fmtflags) and off with unsetf(fmtflags). These flags are shown in the following table.
on/off flag | Effect |
---|---|
ios::skipws | Skip white space. (For input; this is the default.) |
ios::showbase | Indicate the numeric base (as set, for example, by dec, oct, or hex) when printing an integral value. Input streams also recognize the base prefix when showbase is on. |
ios::showpoint | Show decimal point and trailing zeros for floating-point values. |
ios::uppercase | Display uppercase A-F for hexadecimal values and E for scientific values. |
ios::showpos | Show plus sign (+) for positive values. |
ios::unitbuf | "Unit buffering." The stream is flushed after each insertion. |
For example, to show the plus sign for cout, you say cout.setf(ios::showpos). To stop showing the plus sign, you say cout.unsetf(ios::showpos).
The unitbuf flag controls unit buffering, which means that each insertion is flushed to its output stream immediately. This is handy for error tracing, so that in case of a program crash, your data is still written to the log file. The following program illustrates unit buffering.
//: C04:Unitbuf.cpp
#include <cstdlib> // For abort()
#include <fstream>
using namespace std;
int main() {
ofstream out("log.txt");
out.setf(ios::unitbuf);
out << "one\n";
out << "two\n";
abort();
} ///:~
It is necessary to turn on unit buffering before any insertions are made to the stream. When we commented out the call to setf( ), one particular compiler had written only the letter ‘o’ to the file log.txt. With unit buffering, no data was lost.
The standard error output stream cerr has unit buffering turned on by default. There is a cost for unit buffering, of course, so if an output stream is heavily used, don’t enable unit buffering unless efficiency is not a consideration.
Format fields
The second type of formatting flags work in a group. Only one of these flags can be, like the buttons on old car radios—you push one in, the rest pop out. Unfortunately this doesn’t happen automatically, and you have to pay attention to what flags you’re setting so that you don’t accidentally call the wrong setf( ) function. For example, there’s a flag for each of the number bases: hexadecimal, decimal, and octal. Collectively, these flags are referred to as the ios::basefield. If the ios::dec flag is set and you call setf(ios::hex), you’ll set the ios::hex flag, but you won’t clear the ios::dec bit, resulting in undefined behavior. The proper thing to do is call the second form of setf( ) like this: setf(ios::hex, ios::basefield). This function first clears all the bits in the ios::basefield and then sets ios::hex. Thus, this form of setf( ) ensures that the other flags in the group "pop out" whenever you set one. Of course, the ios::hex manipulator does all this for you, automatically, so you don’t have to concern yourself with the internal details of the implementation of this class or to even care that it’s a set of binary flags. Later you’ll see that there are manipulators to provide equivalent functionality in all the places you would use setf( ).
Here are the flag groups and their effects:
ios::basefield | effect |
---|---|
ios::dec | Format integral values in base 10 (decimal) (the default radix—no prefix is visible). |
ios::hex | Format integral values in base 16 (hexadecimal). |
ios::oct | Format integral values in base 8 (octal). |