iostream formatting
The stream operators of lesson 004 write values in a default format. The manipulators change that format: width, fill, precision, base and the words for bool. They are objects you insert into the stream like a value, and they change the stream, not the expression.
The formatting library of lesson 063 does the same job per value and leaves nothing behind. Streams keep their state, which is convenient for a table and a source of surprises in the next function that writes to the same stream.
Every one of these settings belongs to the stream, not to the value, which is why a function that changes one should say so or restore it. A table printed with the manipulators is the classic case where the state is worth setting once and resetting at the end.
The stream as a chain
std::cout << value returns the stream, which is why the calls chain. The type of each argument decides how it is written: an int as digits, a double with six significant digits, a char as a character.
The program writes a line in one chain and then a second with std::flush in the middle. flush pushes the buffer to the operating system without ending the line, which matters when a program waits for input or writes to a pipe.
std::endl is a newline followed by a flush; '\n' is only the newline. In a loop that writes thousands of lines, '\n' is faster because it does not flush each one.
#include <iostream>
int main()
{
int count = 3;
double price = 2.5;
std::cout << "count " << count << ", price " << price << '\n';
std::cout << "before" << std::flush << " after" << '\n';
std::cout << "third line" << std::endl;
}
g++ -std=c++23 -Wall -Wextra chain.cpp -o chain
./chain
count 3, price 2.5
before after
third line
Width, fill and alignment
std::setw sets the width of the next output only. The default alignment is right, std::left and std::right change it, and std::setfill chooses the padding character.
The program prints the same word three times in six columns: right-aligned by default, left-aligned with std::left, and padded with asterisks. The brackets show where the field begins and ends.
Because setw applies to one value, a table needs it before every field, while std::left and std::setfill stay set until they are changed. That difference is the most common reason a table loses its alignment halfway down.
#include <iomanip>
#include <iostream>
int main()
{
std::cout << '[' << std::setw(6) << "id" << ']' << '\n';
std::cout << '[' << std::left << std::setw(6) << "id" << ']' << '\n';
std::cout << '[' << std::setfill('*') << std::setw(6) << 42 << ']' << '\n';
}
g++ -std=c++23 -Wall -Wextra width.cpp -o width
./width
[ id]
[id ]
[42****]
Precision for floating point
The default format of a double prints six significant digits. std::fixed switches to a fixed number of digits after the point, std::setprecision sets how many, and std::scientific uses the exponent form.
The program prints the same value four ways: default, fixed with three decimals, scientific and back to the default with std::defaultfloat. The last line is the reminder that the settings persist.
std::setprecision means digits after the point in fixed and scientific mode, and significant digits in the default mode. The two meanings share one function, which is why a program that changes mode should set the precision again.
#include <iomanip>
#include <iostream>
int main()
{
double value = 2.0 / 3.0;
std::cout << value << '\n';
std::cout << std::fixed << std::setprecision(3) << value << '\n';
std::cout << std::scientific << value << '\n';
std::cout << std::defaultfloat << value << '\n';
}
g++ -std=c++23 -Wall -Wextra precision.cpp -o precision
./precision
0.666667
0.667
6.667e-01
0.667
Bases and booleans
std::hex, std::oct and std::dec choose the base of every integer written afterwards. std::showbase adds the 0x or 0 prefix, and std::boolalpha writes true and false instead of 1 and 0.
The program prints 255 in three bases, then 255 in hexadecimal with the prefix and in decimal again. The two lines show that the base is a stream setting, not an argument.
Every one of these settings stays on the stream. A function that writes a number in hex and returns leaves std::cout in hex for its caller, which is why the stream state is worth resetting at the end of such a function.
#include <iomanip>
#include <iostream>
int main()
{
std::cout << std::hex << 255 << ' ' << std::oct << 255 << ' ' << std::dec << 255 << '\n';
std::cout << std::showbase << std::hex << 255 << std::dec << ' ';
std::cout << std::boolalpha << true << ' ' << false << '\n';
}
g++ -std=c++23 -Wall -Wextra base.cpp -o base
./base
ff 377 255
0xff true false
A manipulator without its header
The manipulators with an argument, such as setw, setfill and setprecision, live in <iomanip>, not in <iostream>. Using one without the header is an unknown name, and the compiler says it is not a member of std.
The program includes only <iostream> and calls std::setprecision. The error names the function and the namespace, and the fix is the missing include, which the compiler cannot suggest because the name is simply absent.
The parameterless manipulators, such as std::hex, std::left and std::boolalpha, are in <ios> and come with <iostream>. That split is why half of a program can compile and the other half cannot.
#include <iostream>
int main()
{
std::cout << std::setprecision(2) << 3.14159 << '\n';
}
g++ -std=c++23 -Wall -Wextra no_iomanip.cpp -o no_iomanip
no_iomanip.cpp: In function 'int main()':
no_iomanip.cpp:5:23: error: 'setprecision' is not a member of 'std'
5 | std::cout << std::setprecision(2) << 3.14159 << '\n';
| ^~~~~~~~~~~~
no_iomanip.cpp:2:1: note: 'std::setprecision' is defined in header '<iomanip>'; this is probably fixable by adding '#include <iomanip>'
1 | #include <iostream>
+++ |+#include <iomanip>
2 |
Exercises
- Print a table of three rows with a name in ten columns and a price in eight, aligned on the decimal point with fixed and setprecision.
- Print the numbers 1 to 5 in decimal, hexadecimal and octal, one base per line.
- Write a function that prints one number in hex and restores the stream to decimal before it returns.
Questions
A new set of questions in a new order every time. Choose one answer for each, then check.
-
What does inserting
std::endldo?Answer
It ends the line and flushes the stream
The manipulator writes the newline and then flushes.
-
Where does
std::setwapply?Answer
To the next output only
The width is reset after one insertion, unlike most other manipulators.
-
What does
std::fixedchange?Answer
The format of floating point output to fixed notation
The floatfield is set to fixed, and setprecision then means digits after the point.
-
What does
std::boolalphado?Answer
It prints bool values as true and false
The flag changes the text of the two bool values.
-
What does this program print?
#include <iostream> int main() { std::cout << "count " << 3 << ", price " << 2.5 << '\n'; std::cout << "before " << "after" << '\n'; std::cout << "third" << " line"; }Answer
count 3, price 2.5 / before after / third line
The chain writes the pieces in order, and 2.5 keeps its short default form.
-
What does this program print?
#include <iomanip> #include <iostream> int main() { std::cout << '[' << std::setw(6) << "id" << "]\n"; std::cout << '[' << std::left << std::setw(6) << "id" << "]\n"; std::cout << '[' << std::right << std::setfill('*') << std::setw(6) << 42 << "]"; }Answer
[ id] / [id ] / [****42]
The first line is right-aligned by default, the second left-aligned, and the fill pads the number.
-
What does this program print?
#include <iomanip> #include <iostream> int main() { std::cout << 2.0 / 3.0 << '\n'; std::cout << std::fixed << std::setprecision(3) << 2.0 / 3.0 << '\n'; std::cout << std::scientific << std::setprecision(3) << 2.0 / 3.0 << '\n'; std::cout << std::defaultfloat << std::setprecision(3) << 2.0 / 3.0; }Answer
0.666667 / 0.667 / 6.667e-01 / 0.667
The default, fixed, scientific and default-float formats each print the value in their own shape.
-
What does this program print?
#include <iomanip> #include <iostream> int main() { std::cout << std::hex << 255 << ' ' << std::oct << 255 << ' ' << std::dec << 255 << '\n'; std::cout << std::showbase << std::hex << 255 << ' ' << std::boolalpha << (1 == 1) << ' ' << (1 == 2); }Answer
ff 377 255 / 0xff true false
The base manipulators print the first line, and showbase plus boolalpha print the second.
-
What does the compiler report for this line?
#include <iostream> int main() { std::cout << std::setprecision(2) << 3.14159 << '\n'; }Answer
'setprecision' is not a member of 'std'
The manipulator lives in <iomanip>, and the note names the missing header.
-
Why prefer the format library over the manipulators for new code?
Answer
The format string is checked and the layout is local to the call
The stream flags are global to the stream and easy to leave changed.
The code on this page was built with g++ 15.2.0 and run on Alpine Linux 3.24.3 (x86_64) in a Docker container. The programs whose section shows a compiler error were compiled until that error and were not run.
Article author: Arthur Isaev