Show Lecture.Manipulators as a slide show.
CS253 Manipulators
Overview
- I/O manipulators change the state of an I/O stream.
- E.g.,
cout << hex;
sets cout to hexadecimal output mode.
- This change is persistent, or sticky. It stays until changed
again.
- An output stream “knows” its current base, width,
fixed/scientific style, precision, etc.
- Every stream has its own, separate, state. This shows how
cout and cerr can have different output precision:
cout << 40/33.0L << "\n\n";
cout << setprecision(25);
cout << 40/33.0L << "\n";
cerr << 40/33.0L << "\n";
cout << 40/33.0L << "\n";
1.21212
1.212121212121212121244976
1.21212
1.212121212121212121244976
I/O Manipulators
cout << false << ' ' << true << '\n'
<< boolalpha << false << ' ' << true << '\n'
<< noboolalpha << false << ' ' << true << '\n';
0 1
false true
0 1
- Boolean output, by default, shows as
0
or 1
.
- boolalpha changes that to writing false or true.
cout << dec << 65 << ' ' << hex << 65 << ' ' << oct << 65 << '\n'
<< showbase << dec << 65 << ' ' << hex << 65 << ' ' << oct << 65 << '\n'
<< noshowbase << dec << 65 << ' ' << hex << 65 << ' ' << oct << 65 << '\n';
65 41 101
65 0x41 0101
65 41 101
- Label integer output, using the same conventions as integer constants
in a C++ program:
- Prefix hex integer output with
0x
.
- Ensure that octal integer output starts with a
0
.
- There is no binary output.
cout << 123.0 << ' ' << 456.789 << '\n'
<< showpoint << 123.0 << ' ' << 456.789 << '\n'
<< noshowpoint << 123.0 << ' ' << 456.789 << '\n';
123 456.789
123.000 456.789
123 456.789
- Floating-point numbers get a decimal point, whether or not
they’re whole numbers.
cout << 123 << ' ' << 0 << ' ' << -456 << '\n'
<< showpos << 123 << ' ' << 0 << ' ' << -456 << '\n'
<< noshowpos << 123 << ' ' << 0 << ' ' << -456 << '\n';
123 0 -456
+123 +0 -456
123 0 -456
- Non-negative numbers gets a plus sign.
istringstream iss;
int a;
iss.str("\n\r\v\f 123 ");
iss >> a;
cout << (iss?"good":"bad") << ' ' << a << '\n';
iss.str("\n\r\v\f 456 ");
iss >> skipws >> a;
cout << (iss?"good":"bad") << ' ' << a << '\n';
iss.str("\n\r\v\f 789 ");
iss >> noskipws >> a;
cout << (iss?"good":"bad") << ' ' << a << '\n';
good 123
good 456
bad 0
- Whitespace is normally skipped before formatted input (
<<
).
cout << hex << 64206 << ' ' << 1e99 << " end\n"
<< uppercase << hex << 64206 << ' ' << 1e99 << " end\n"
<< nouppercase << hex << 64206 << ' ' << 1e99 << " end\n";
face 1e+99 end
FACE 1E+99 end
face 1e+99 end
- Use UPPERCASE letters in hex output, and in floating-point exponents.
- Strings and characters are unchanged.
cout << setw(5) << 1 << 2 << 3 << 4 << '\n';
1234
cout << setw(9) << 6.7 << '\n'
<< setw(9) << 'x' << '\n'
<< setw(9) << "foo" << '\n';
6.7
x
foo
cout << setfill('*') << setw(4) << 8.9 << '\n'
<< setw(4) << 'y' << '\n'
<< setw(4) << "bar" << '\n'
<< setw(4) << "alpha" << '\n';
*8.9
***y
*bar
alpha
- setw is different. It’s not sticky—it only applies
to the very next formatted output. It’s only good for one conversion.
- It affects more than just numbers.
- It pads with the fill character from setfill, default is space.
cout << "▻" << 123 << "◅\n"
<< "▻" << setw(6) << left << 123 << "◅\n"
<< "▻" << setw(6) << right << 123 << "◅\n"
<< "▻" << setw(6) << internal << 123 << "◅\n"
<< "▻" << -456 << "◅\n"
<< "▻" << setw(6) << left << -456 << "◅\n"
<< "▻" << setw(6) << right << -456 << "◅\n"
<< "▻" << setw(6) << internal << -456 << "◅\n"
<< "▻" "ABC" << "◅\n"
<< "▻" << setw(6) << left << "DE" << "◅\n"
<< "▻" << setw(6) << right << 'F' << "◅\n";
▻123◅
▻123 ◅
▻ 123◅
▻ 123◅
▻-456◅
▻-456 ◅
▻ -456◅
▻- 456◅
▻ABC◅
▻DE ◅
▻ F◅
cout << setfill(':')
<< "▻" << -7.8 << "◅\n"
<< "▻" << setw(6) << left << -7.8 << "◅\n"
<< "▻" << setw(6) << right << -7.8 << "◅\n"
<< "▻" << setw(6) << internal << -7.8 << "◅\n";
▻-7.8◅
▻-7.8::◅
▻::-7.8◅
▻-::7.8◅
- Alignment for numbers and strings.
There is no
center
.
Notation can be tricky
Left alignment means that the number or string is touching the
left wall of its field. Therefore, the padding is on the other
side, or, right. left/right says where the data goes,
not the padding.
cout << "▻" << setw(5) << left << "LLL" << "◅\n"
<< "▻" << setw(5) << right << "RRR" << "◅\n";
▻LLL ◅
▻ RRR◅
Strings are often left-aligned, whereas numbers are right-aligned:
Country | ☏ Code | Country | ☏ Code |
United States | 1 | Republic of the Congo | 242 |
Egypt | 20 | Democratic Republic of the Congo | 243 |
Russia | 7 | Peru | 51 |
Hong Kong | 852 | Canada | 1 |
cout << 10 << ' ' << 30 << ' ' << 50 << '\n'
<< dec << 10 << ' ' << 30 << ' ' << 50 << '\n'
<< oct << 10 << ' ' << 30 << ' ' << 50 << '\n'
<< hex << 10 << ' ' << 30 << ' ' << 50 << '\n';
10 30 50
10 30 50
12 36 62
a 1e 32
- Output in base 10, base 8, and base 16.
cout << bin << 10;
c.cc:1: error: 'bin' was not declared in this scope
- There is no base 2 output.
cout << 16e5 << ' ' << 3.14159 << ' ' << 4.5e-12 << '\n'
<< fixed << 16e5 << ' ' << 3.14159 << ' ' << 4.5e-12 << '\n'
<< scientific << 16e5 << ' ' << 3.14159 << ' ' << 4.5e-12 << '\n'
<< hexfloat << 16e5 << ' ' << 3.14159 << ' ' << 4.5e-12 << '\n'
<< defaultfloat << 16e5 << ' ' << 3.14159 << ' ' << 4.5e-12 << '\n';
1.6e+06 3.14159 4.5e-12
1600000.000000 3.141590 0.000000
1.600000e+06 3.141590e+00 4.500000e-12
0x1.86ap+20 0x1.921f9f01b866ep+1 0x1.3ca8cb153a753p-38
1.6e+06 3.14159 4.5e-12
- Fixed-point notation: no exponent
- Scientific notation: digit
.
digits e
exponent
- Hexadecimal: the bits that represent the number
- Default: choose based on which one makes sense.
cout << 123 << '\n'
<< setw(10) << 456 << '\n'
<< setfill('*') << setw(10) << 789 << '\n';
123
456
*******789
- Set the fill (padding) character, which defaults to a space.
- Only relevant if setw is used.
https://cplusplus.com/reference/ios/ios_base/precision/ says:
- Using the default floating-point notation, the precision field specifies the maximum number of meaningful digits to display in total counting both those before and those after the decimal point. Notice that it is not a minimum, and therefore it does not pad the displayed number with trailing zeros if the number can be displayed with less digits than the precision.
- In both the fixed and scientific notations, the precision field specifies exactly how many digits to display after the decimal point, even if this includes trailing decimal zeros. The digits before the decimal point are not relevant for the precision in this case.
cout << 123.45 << '\n'
<< setprecision(1) << 123.45 << '\n'
<< setprecision(9) << 123.45 << '\n';
123.45
1e+02
123.45
cout << fixed
<< 123.45 << '\n'
<< setprecision(1) << 123.45 << '\n'
<< setprecision(9) << 123.45 << '\n';
123.450000
123.5
123.450000000
cout << scientific
<< 123.45 << '\n'
<< setprecision(1) << 123.45 << '\n'
<< setprecision(9) << 123.45 << '\n';
1.234500e+02
1.2e+02
1.234500000e+02
Etiquette
void showhex(int n) {
cout << hex << setw(8) << setfill('0') << n << '\n';
}
int main() {
showhex(100);
cout << 42 << '\n';
}
00000064
2a
It’s rude to change a global resource. showhex()
’s job is to
display a number, not to display a number and change the state
of cout.
main() didn’t expect the base of cout, or its fill character, to get
changed. Now, of course, if it’s main() that’s changing those settings,
who else would complain? Well, perhaps main() calls general-purpose
functions that don’t work well if the settings of cout are changed.
Etiquette
void showhex(int n) {
const auto save_flags = cout.flags();
const auto save_fill = cout.fill();
cout << hex << setw(8) << setfill('0') << n << '\n';
cout.flags(save_flags);
cout.fill(save_fill);
}
int main() {
showhex(100);
cout << 42 << '\n';
}
00000064
42
Defining Your Own
It’s easy to define your own I/O manipulators:
ostream &dog(ostream &os) {
return os << "Kokopelli";
}
int main() {
cout << "My dog is " << dog << ".\n";
return 0;
}
My dog is Kokopelli.
Of course, if that’s all you want:
const string dog = "Kokopelli";
cout << "My dog is " << dog << ".\n";
My dog is Kokopelli.
Better Example
ostream &bucks(ostream &os) {
return os << fixed << setprecision(2);
}
int main() {
cout << 34.5 << ' ' << bucks << 78.9 << '\n';
return 0;
}
34.5 78.90
- This sets output to be two digits after the decimal point,
as is traditional for money in the USA.
C++20
Traditional C++ formatting:
cout << "The square root of " << n << " is " << fixed(2) << sqrt(n) << '\n';
Using format:
cout << format("The square root of {} is {:.2}\n", n, sqrt(n));