The I/O Stream Classes let you define how output should be formatted on a stream-by-stream basis within your program. Most formatting applies to numeric data: what base integers should be written to the output stream in, how many digits of precision floating-point numbers should have, whether they should appear in scientific or fixed-point format. Other formatting applies to any of the built-in types, and to your own types if you design your class output operators to check the format state of a stream to determine what formatting action to take.
This section describes a number of techniques you can use to change the way data is written to output streams. One common characteristic of most of the methods described (other than the method of changing the output field's width) is that each format state setting applies to its output stream until it is explicitly cleared, or is overridden by a mutually exclusive format state. This differs from the C printf() family of output functions, in which each printf() statement must define its formatting information individually.
For some of the format flags defined for the ios class, you can set or clear them using an ios function and a flag name, or by using a manipulator. With manipulators you can place the change to a stream's state within a list of outputs for that stream. The following example shows two ways of changing the base of an output stream from decimal to octal. The first, which is more difficult to read, uses the setf() function to set the basefield field in the format state to octal. The second way uses a manipulator, oct, within the output statement, to accomplish the same thing:
#include <iostream.h> void main() { int a=9; cout.setf(ios::oct,ios::basefield); cout << a << endl; // assume format state gets changed here, so we must change it back cout << oct << a << endl; }
Note that you do not need to qualify a manipulator, provided you do not create a variable or function of the same name as the manipulator. If a variable oct were declared at the start of the above example, cout << oct ... would write the variable oct to standard output. cout << ios::oct ... would change the format state.
There are two versions of the setf() function of ios. One version takes a single long value newset as argument; its effect is to set any flags set in newset, without affecting other flags. This version is useful for setting flags that are not mutually exclusive with other flags (for example, ios::uppercase). The other version takes two long values as arguments. The first argument determines what flags to set, and the second argument determines which groups of flags to clear before any flags are set. The second argument lets you clear a group of flags before setting one of that group. The second argument is useful for flags that are mutually exclusive. If you try to change the base field of the cout output stream using cout.setf(ios::oct);, setf() sets ios::oct but it does not clear ios::dec if it is set, so that integers continue to be written to cout in decimal notation. However, if you use cout.setf(ios::oct,ios::basefield);, all bits in basefield are cleared (oct, dec, and hex) before oct is set, so that integers are then written to cout in octal notation.
To clear format state flags, you can use the unsetf() function, which takes a single argument indicating which flags to clear.
To set the format state to a particular combination of flags (without regard for the pre-existing format state), you can use the flags(long flagset) member function of ios. The value of flagset determines the resulting values of all the flags of the format state.
The following example demonstrates the use of flags(), setf(), and unsetf(). The main() function changes the flags as follows:
The function showFlags() determines and displays the current flag settings. It obtains the value of the settings using flags(), and then excludes ios::oct from the result before displaying the result in octal. This exclusion is done to display the result in octal without causing the octal setting for ios::basefield to show up in the program's output.
//Using flags(), flags(long), setf(long), and setf(long,long)
#include <iostream.h>
void showFlags() { // save altered flag settings, but clear ios::oct from them long flagSettings = cout.flags() & (~ios::oct) ; // display those flag settings in octal cout << oct << flagSettings << endl; }
void main () { // get and display current flag settings using flags() cout << "flags(): "; long originalFlags = cout.flags(); showFlags();
// change format state using flags(long) cout << "flags(ios::fixed): "; cout.flags(ios::fixed); showFlags();
// change adjust field using setf(long) cout << "setf(ios::right): "; cout.setf(ios::right); showFlags();
// change floatfield using setf(long, long) cout << "setf(ios::scientific | ios::left,\n" << "ios::floatfield | ios::adjustfield): "; cout.setf(ios::scientific | ios::left,ios::floatfield |ios::adjustfield); showFlags();
// reset to original setting cout << "flags(originalFlags): "; cout.flags(originalFlags); showFlags(); }
This example produces the following output:
flags(): 21 flags(ios::fixed): 10000 setf(ios::right): 10004 setf(ios::scientific | ios::left, ios::floatfield | ios::adjustfield): 4002 flags(originalFlags): 21
Note: If you specify conflicting flags, the results are unpredictable. For example, the results will be unpredictable if you set both ios::left and ios::right in the format state of iosobj. You should set only one flag in each set of the following three sets:
- ios::left, ios::right, ios::internal
- ios::dec, ios::oct, ios::hex
- ios::scientific, ios::fixed.
You can change the notation and precision of floating-point values to match your program's output requirements. To change the precision with which floating-point values are written to output streams, use ios::precision(). By default, an output stream writes float and double values using six significant digits. The following example changes the precision for the cout predefined stream to 17:
cout.precision(17);
You can also change between scientific and fixed notations for floating-point values. Use the two-parameter version of the setf() member function of ios to set the appropriate notation. The first argument indicates the flag to be set; the second argument indicates the field of flags the change applies to. For example, to change the notation of an output stream called File6, use:
File6.setf(ios::scientific,ios::floatfield);
This statement clears the settings of the ios::floatfield field and then sets it to ios::scientific.
The ios::uppercase format state variable affects whether the "e" used in scientific-notation floating-point values is in uppercase or lowercase. By default, it is in lowercase. To change the setting to uppercase for an output stream called TaskQueue, use:
TaskQueue.setf(ios::uppercase);
The following example shows the effect on floating-point output of changes made to an output stream using ios format state flags and the precision member function:
// How format state flags and precision() affect output
#include <iostream.h>
void main() { double a=3.14159265358979323846; double b; long originalFlags=cout.flags(); int originalPrecision=cout.precision(); for (double exp=1.;exp<1.0E+25;exp*=100000000.) { cout << "Printing new value for b:\n"; b=a*exp; // Initialize b to a larger magnitude of a
// Now print b in a number of ways: // In fixed decimal notation cout.setf(ios::fixed,ios::floatfield); cout << " " << b << '\n'; // In scientific notation cout.setf(ios::scientific,ios::floatfield); cout << " " <<b << '\n'; // Change the exponent from lower to uppercase cout.setf(ios::uppercase); cout << " " <<b << '\n'; // With 12 digits of precision, scientific notation cout.precision(12); cout << " " <<b << '\n'; // Same precision, fixed notation cout.setf(ios::fixed,ios::floatfield); // Now set everything back to defaults cout.flags(originalFlags); cout.precision(originalPrecision); } }
The output from this program is:
Printing new value for b: 3.141593 3.141593e+00 3.141593E+00 3.141592653590E+00 Printing new value for b: 314159265.358979 3.141593e+08 3.141593E+08 3.141592653590E+08 Printing new value for b: 31415926535897932.000000 3.141593e+16 3.141593E+16 3.141592653590E+16 Printing new value for b: 3141592653589792800000000.000000 3.141593e+24 3.141593E+24 3.141592653590E+24
For output of integral values, you can choose decimal, hexadecimal, or octal notation. You can either use setf() to set the appropriate ios flag, or you can place the appropriate parameterized manipulator in the output stream. The following example shows both methods:
//Showing the base of integer values
#include <iostream.h> #include <iomanip.h>
void main() { int a=148; cout.setf(ios::showbase); // show the base of all integral output: // leading 0x means hexadecimal, // leading 01 to 07 means octal, // leading 1 to 9 means decimal cout.setf(ios::oct,ios::basefield); // change format state to octal cout << a << '\n'; cout.setf(ios::dec,ios::basefield); // change format state to decimal cout << a << '\n'; cout.setf(ios::hex,ios::basefield); // change format state to hexadecimal cout << a << '\n'; cout << oct << a << '\n'; // Parameterized manipulators clear the cout << dec << a << '\n'; // basefield, then set the appropriate cout << hex << a << '\n'; // flag within basefield. }
The ios::showbase flag determines whether numbers in octal or hexadecimal notation are written to the output stream with a leading "0" or "0x", respectively. You can set ios::showbase where you intend to use the output as input to an I/O Stream input stream later on. If you do not set ios::showbase and you try to use the output as input to another stream, octal values and those hexadecimal values that do not contain the digits a-f will be interpreted as decimal values; hexadecimal values that do contain any of the digits a-f will cause an input stream error.
For built-in types, the output operator does not write any leading or trailing spaces around values being written to an output stream, unless you explicitly set the field width of the output stream, using the width() member function of ios or the setw() parameterized manipulator. Both width() and setw() have only a short-term effect on output. As soon as a value is written to the output stream, the field width is reset, so that once again no leading or trailing spaces are inserted. If you want leading or trailing blanks to appear on successively written values, you can use the setw() manipulator within the output statement. For example:
#include <iostream.h> #include <iomanip.h> // required for use of setw() void main() { int i=-5,j=7,k=-9; cout << setw(5) << i << setw(5) << j << setw(5) << k << endl; }
You can also specify how values should be formatted within their fields. If the current width setting is greater than the number of characters required for the output, you can choose between right justification (the default), left justification, or, for numeric values, internal justification (the sign, if any, is left-justified, while the value is right-justified). For example, the output statement above could be replaced with:
cout << setw(5) << i; // -5 cout.setf(ios::left,ios::adjustfield); cout << setw(5) << j; // 7 cout.setf(ios::internal,ios::adjustfield); cout << setw(5) << k << endl; // -9
The following shows two lines of output, the first from the original example, and the second after the output statement has been modified to use the field justification shown above:
-5 7 -9 -57 - 9
Defining an Output
Operator for a Class Type