CS253: Software Development with C++

Spring 2023

Manipulators

Show Lecture.Manipulators as a slide show.

CS253 Manipulators

Overview

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

<iostream><iomanip>
These don’t take an argumentThese do take an argument
[no]boolalpharesetiosflags
[no]showbasesetiosflags
[no]showpointsetbase
[no]showpossetfill
[no]skipwssetprecision
[no]uppercasesetw (non-sticky)
left / right / internal 
dec / hex / oct 
fixed / scientific 

[no]boolalpha

cout                << false << ' ' << true << '\n'
     << boolalpha   << false << ' ' << true << '\n'
     << noboolalpha << false << ' ' << true << '\n';
0 1
false true
0 1

[no]showbase

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

[no]showpoint

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

[no]showpos

cout              << -123 << ' ' << 0 << ' ' << 456 << '\n'
     << showpos   << -123 << ' ' << 0 << ' ' << 456 << '\n'
     << noshowpos << -123 << ' ' << 0 << ' ' << 456 << '\n';
-123 0 456
-123 +0 +456
-123 0 456

[no]skipws

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

[no]uppercase

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

setw

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

left / right / internal

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◅

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☏ CodeCountry☏ Code
United States1Republic of the Congo242
Egypt20Democratic Republic of the Congo243
Russia7Peru51
Hong Kong852Canada1

dec / oct / hex

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
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

fixed / scientific / hexfloat / defaultfloat

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

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

setfill

cout                             << 123 << '\n'
                     << setw(10) << 456 << '\n'
     << setfill('*') << setw(10) << 789 << '\n';
123
       456
*******789

setprecision

https://cplusplus.com/reference/ios/ios_base/precision/ says:

setprecision

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 << "🐶";
}

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

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