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
- Every number gets a sign, be it negative, zero, or positive.
istringstream iss;
int a;
iss.str("\t\n\r\v\f 123 ");
iss >> a;
cout << (iss?"good":"bad") << ' ' << a << '\n';
iss.str("\t\n\r\v\f 456 ");
iss >> skipws >> a;
cout << (iss?"good":"bad") << ' ' << a << '\n';
iss.str("\t\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 << 1 << setw(5) << 2 << 3 << 4 << '\n';
1 234
cout << "☢" << setw(7) << 6.7 << '\n'
<< "☢" << setw(7) << 'x' << '\n'
<< "☢" << setw(7) << "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) << 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◅
▻ 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(12) << left << "sinister" << "◅\n"
<< "▻" << setw(12) << right << "dexter" << "◅\n";
▻sinister ◅
▻ dexter◅
Strings are often left-aligned; numbers are customarily 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 (sorry, no base 2).
istringstream iss("12 0x34 56 78");
int a, b, c, d;
if (iss >> hex >> a >> b >> oct >> c >> dec >> d)
cout << a << ' ' << b << ' ' << c << ' ' << d;
18 52 46 78
- Input in base 16, base 8, and base 10.
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: do what makes sense based on the magnitude of the number
Not the same
defaultfloat is sometimes different from both
fixed and scientific:
cout << 1.234 << '\n'
<< defaultfloat << 1.234 << '\n'
<< fixed << 1.234 << '\n'
<< scientific << 1.234 << '\n';
1.234
1.234
1.234000
1.234000e+00
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
.flags()
saves or restores the flags: hex/oct/dec,
fixed/scientific, showbase, etc.
.fill()
saves or restores the fill character.
- Note the technique of using the same name for a getter/setter pair.
It always returns the previous value.
Defining Your Own
It’s easy to define your own I/O manipulators:
ostream& dog(ostream &os) {
return os << "🐶";
}
int main() {
cout << "My dog is " << dog << ".\n";
return 0;
}
My dog is 🐶.
Of course, if that’s all you want:
constexpr auto dog = "🐶";
cout << "My dog is " << dog << ".\n";
My dog is 🐶.
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 USD.
History of Formatting
Verbose? You bet! C++20 has format.
♫ Someday, my prints will come ♫
Traditional C formatting:
printf("√̅2 = %.3f\n", sqrt(2));
√̅2 = 1.414
Traditional C++ formatting:
cout << "√̅2 = " << fixed << setprecision(3) << sqrt(2) << '\n';
√̅2 = 1.414
Using C++20’s format:
cout << format("√̅2 = {:.3}\n", sqrt(2));
c.cc:1: error: ‘format’ was not declared in this scope