一、概述
<iomanip> 是 C++ 标准库中的头文件,全称是 Input/Output Manipulators (输入/输出操纵器)。它提供了一组带参数的流操纵器 ,用于格式化输入输出。与 <iostream> 中无参数的操纵器(如 endl、hex、fixed)不同,<iomanip> 中的操纵器接受一个或多个参数,因此需要单独包含此头文件。
包含方式:
cpp
#include <iomanip>
二、核心原理
<iomanip> 中的操纵器返回一个未指定的实现类型 (如 T1、T2...),这些类型重载了 operator>>和 operator<<,使得操纵器可以直接与流对象配合使用。
cpp
// 原理示意:setw 返回一个临时对象,该对象在插入流时调用 str.width(n)
cout << setw(10) << x;
// 等价于
cout.width(10);
cout << x;
这种设计使得多个操纵器可以链式调用,代码简洁明了。
三、操纵器详解
1. 宽度控制:setw(int n)
设置下一个输入/输出字段的最小宽度为 n 个字符。
| 特性 | 说明 |
|---|---|
| 作用范围 | 仅对下一个输出有效,之后自动重置为默认值(0表示自适应) |
| 对齐方式 | 默认为右对齐 |
| 填充字符 | 默认为空格,可通过 setfill 修改 |
| 适用范围 | 数值类型和字符串,不直接应用于 char 或 string 类型 |
cpp
cout << setw(10) << "Hello" << endl;
// 输出: " Hello"(右对齐,宽度10)
cout << setw(5) << 123 << endl;
// 输出: " 123"
cout << setw(3) << 12345 << endl;
// 输出: "12345"(宽度不足时自动扩展)
2. 精度控制:setprecision(int n)
设置浮点数的精度。其具体含义取决于浮点数格式模式的设置。
| 模式 | setprecision 的含义 |
|---|---|
| 默认模式 | 有效数字的总位数(包括整数和小数部分) |
fixed 模式 |
小数点后的位数 |
scientific 模式 |
小数点后的位数(有效数字 = 整数部分1位 + 精度值) |
cpp
double pi = 3.14159265358979;
// 默认模式:有效数字
cout << setprecision(5) << pi << endl; // 3.1416
// fixed 模式:小数位数
cout << fixed << setprecision(3) << pi << endl; // 3.142
// scientific 模式:小数位数
cout << scientific << setprecision(4) << pi << endl; // 3.1416e+00
3. 填充字符:setfill(char c)
设置填充字符,当实际内容宽度小于 setw 设置的宽度时,使用此字符填充剩余空间。
cpp
cout << setfill('*') << setw(10) << 123 << endl;
// 输出: "*******123"
cout << setfill('-') << setw(8) << left << "Hi" << endl;
// 输出: "Hi------"
注意 :setfill 的效果会持续有效,直到下次修改。
4. 格式标志设置:setiosflags(ios_base::fmtflags mask)
设置指定的格式标志。常用标志包括:
| 标志 | 作用 |
|---|---|
ios::left |
左对齐 |
ios::right |
右对齐 |
ios::fixed |
定点小数表示法 |
ios::scientific |
科学计数法 |
ios::showpos |
正数显示 + 号 |
ios::showpoint |
始终显示小数点 |
ios::uppercase |
科学计数法使用大写 E |
ios::unitbuf |
每次输出后刷新缓冲区 |
cpp
cout << setiosflags(ios::left | ios::showpos);
cout << setw(10) << 42 << endl;
// 输出: "+42 "
5. 格式标志清除:resetiosflags(ios_base::fmtflags mask)
清除指定的格式标志。
cpp
5. 格式标志清除:resetiosflags(ios_base::fmtflags mask)
清除指定的格式标志。
6. 进制设置:setbase(int base)
设置整数输出的进制。合法参数为 8、10、16,其他值会恢复为默认的十进制。
cpp
cout << setbase(16) << 255 << endl; // ff(小写)
cout << setbase(8) << 64 << endl; // 100
cout << setbase(10) << 0x2A << endl; // 42
便捷替代 :<iostream> 中提供了无参的 dec、hex、oct 操纵器,使用更方便。
7. 高级操纵器(C++11)
(1)quoted:处理带空格的字符串
自动处理引号转义,适合读写带空格的文本。
cpp
string s = "Hello World";
cout << quoted(s) << endl; // 输出: "Hello World"
string input;
cin >> quoted(input); // 读取被引号包围的字符串
(2)get_money 和 put_money:货币格式化
cpp
long double money;
cin >> get_money(money, true); // 读取货币值(true表示国际格式)
cout << put_money(12345.67, false); // 输出货币值
(3)get_time 和 put_time:日期时间格式化
cpp
#include <ctime>
struct tm t = {};
cin >> get_time(&t, "%Y-%m-%d");
cout << put_time(&t, "%c");
四、常用组合示例
示例1:表格对齐
cpp
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout << left
<< setw(10) << "Name"
<< setw(10) << "Score"
<< setw(10) << "Grade" << endl;
cout << setfill('-') << setw(30) << "" << setfill(' ') << endl;
cout << setw(10) << "Alice"
<< setw(10) << "95"
<< setw(10) << "A" << endl;
cout << setw(10) << "Bob"
<< setw(10) << "87"
<< setw(10) << "B+" << endl;
return 0;
}
输出:
示例2:浮点数格式化
cpp
double values[] = {3.14159, 123.456, 0.00012345};
cout << fixed << setprecision(2);
for (double v : values) {
cout << setw(10) << v << endl;
}
// 输出:
// 3.14
// 123.46
// 0.00
cout << scientific << setprecision(4);
for (double v : values) {
cout << setw(12) << v << endl;
}
// 输出:
// 3.1416e+00
// 1.2346e+02
// 1.2345e-04
示例3:综合应用
cpp
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double PI = 3.14159265358979;
// 默认格式
cout << "默认: " << PI << endl;
// 固定小数位 + 正号 + 宽度
cout << fixed << setprecision(3) << showpos;
cout << "固定3位小数: " << setw(12) << PI << endl;
// 科学计数法 + 大写 + 无正号
cout << scientific << uppercase << noshowpos;
cout << "科学计数法: " << setw(12) << PI * 1000 << endl;
return 0;
}
输出:
bash
默认: 3.14159
固定3位小数: +3.142
科学计数法: 3.1416E+00
五、重要注意事项
1.setw 的单次生效特性
- 这是最容易出错的地方。
setw仅对紧随其后的单个输出有效,之后自动重置。
cpp
cout << setw(10) << 123 << 456 << endl;
// 输出: " 123456"(456 没有应用宽度)
2.setprecision 与格式模式的配合
- 精度含义随
fixed/scientific模式变化,使用时需明确当前模式,即操纵器的持久性。
- 一次性:
setw\ - 持久性:
setfill、setprecision、setiosflags、进制设置等,修改后一直有效直到再次修改
3.标志的组合使用
- 多个标志可以通过
|运算符组合:
cpp
cout << setiosflags(ios::left | ios::showpos | ios::showpoint);
4.保存与恢复格式
为避免格式设置污染后续代码,建议保存原始状态:
cpp
ios_base::fmtflags old_flags = cout.flags();
streamsize old_prec = cout.precision();
char old_fill = cout.fill();
// ... 进行格式设置和输出 ...
cout.flags(old_flags);
cout.precision(old_prec);
cout.fill(old_fill);
六、与 <iostream> 无参操纵器的对比
| 头文件 | 操纵器示例 | 特点 |
|---|---|---|
<iostream> |
endl, dec, hex, oct, left, right, fixed, scientific |
无参数,已包含在 <iostream> 中 |
<iomanip> |
setw(), setprecision(), setfill(), setiosflags(), resetiosflags(), quoted() |
带参数,需显式包含头文件 |
注意 :left、right、fixed 等无参操纵器已在 <iostream> 中提供,不需要 <iomanip>。
七、总结
<iomanip> 是 C++ 格式化 I/O 的核心工具,主要提供:
| 类别 | 操纵器 | 核心用途 |
|---|---|---|
| 宽度填充 | setw, setfill |
控制字段宽度和对齐 |
| 精度控制 | setprecision |
控制浮点数输出精度 |
| 格式标志 | setiosflags, resetiosflags |
精细控制各种格式选项 |
| 进制转换 | setbase |
整数进制输出 |
| 高级功能 | quoted, get_money, get_time |
特殊数据类型处理 |
理解每个操纵器的作用范围 (单次 vs 持久)和适用场景,是正确使用该库的关键。合理运用这些操纵器,可以大大提升程序输出的可读性和专业性。