C++使用 ostream 和 ios 进行输出

本节将详细探讨 <iostream> 输出类 ostream 的各项功能。

插入运算符(<<

插入运算符(<<)用于向输出流写入数据。C++ 对所有内置类型均已预定义插入操作,也允许为自定义类重载该运算符。

在前面的课程中,你已看到 istreamostream 均派生自 iosios(以及 ios_base)的职责之一便是控制输出的格式选项。

格式设置

修改格式有两种途径:标志位(flags)操控符(manipulators)

  • 标志位可视为布尔开关,通过 setf()/unsetf() 进行开/关。
  • 操控符是插入流中的对象,用于影响输入/输出的格式。

示例:默认情况下,正数前不输出 + 号;使用 std::ios::showpos 可改变此行为:

std::cout.setf(std::ios::showpos); // 打开 showpos 标志
std::cout << 27 << '\n';           // 输出 +27

可用按位或(|)同时打开多个标志:

std::cout.setf(std::ios::showpos | std::ios::uppercase);
std::cout << 1234567.89f << '\n';  // 输出 +1.23457E+06

关闭标志使用 unsetf()

std::cout.setf(std::ios::showpos);
std::cout << 27 << '\n';
std::cout.unsetf(std::ios::showpos);
std::cout << 28 << '\n';
// 输出:
// +27
// 28

格式组(format groups)的注意事项

某些标志属于同一格式组,彼此互斥。例如,basefield 组包含 dechexoct,默认启用 dec

std::cout.setf(std::ios::hex); // 仅打开 hex,但未关闭 dec
std::cout << 27 << '\n';       // 仍输出 27(未生效)

解决方法:

  1. 手动关闭冲突标志:
std::cout.unsetf(std::ios::dec);
std::cout.setf(std::ios::hex);
std::cout << 27 << '\n';       // 输出 1b
  1. 使用双参数 setf():传入欲设置标志及其所属格式组,组内其他标志自动关闭:
std::cout.setf(std::ios::hex, std::ios::basefield);
std::cout << 27 << '\n';       // 输出 1b

操控符(manipulators)

使用操控符通常比手动开关标志更方便。例如:

std::cout << std::hex << 27 << '\n'; // 十六进制输出
std::cout << 28 << '\n';             // 仍在十六进制
std::cout << std::dec << 29 << '\n'; // 恢复十进制
// 输出:
// 1b
// 1c
// 29

常用格式控制一览

下表列出常用标志、操控符及成员函数。标志位于 std::ios;操控符位于 std 命名空间;成员函数位于 std::ostream

分组标志含义
std::ios::boolalpha布尔值输出 true/false;否则输出 0/1
操控符含义
std::boolalpha / std::noboolalpha切换布尔文本/数字输出

示例:

std::cout << true << ' ' << false << '\n';      // 1 0
std::cout.setf(std::ios::boolalpha);
std::cout << true << ' ' << false << '\n';      // true false
std::cout << std::noboolalpha << true << ' ' << false << '\n'; // 1 0
分组标志含义
std::ios::showpos正数前显示 +
操控符含义
std::showpos / std::noshowpos切换正数前是否显示 +

示例:

std::cout << 5 << '\n';        // 5
std::cout.setf(std::ios::showpos);
std::cout << 5 << '\n';        // +5
std::cout << std::noshowpos << 5 << '\n'; // 5
分组标志含义
std::ios::uppercase十六进制/科学计数法使用大写字母
操控符含义
std::uppercase / std::nouppercase切换大小写

示例:

std::cout << 12345678.9 << '\n';          // 1.23457e+007
std::cout.setf(std::ios::uppercase);
std::cout << 12345678.9 << '\n';          // 1.23457E+007
分组标志含义
std::ios::basefieldstd::ios::dec十进制(默认)
std::ios::hex十六进制
std::ios::oct八进制
操控符含义
std::dec / std::hex / std::oct切换进制

示例:

std::cout << 27 << '\n';                    // 27
std::cout << std::hex << 27 << '\n';        // 1b
std::cout << std::oct << 27 << '\n';        // 33

精度、计数法与小数点

通过操控符或标志可控制浮点数的显示精度与格式。

分组标志含义
std::ios::floatfieldstd::ios::fixed定点表示
std::ios::scientific科学计数法
std::ios::showpoint始终显示小数点及尾随零
操控符含义
std::fixed / std::scientific切换定点/科学计数法
std::showpoint / std::noshowpoint切换是否强制显示小数点
std::setprecision(int)设置浮点精度(位于 <iomanip>

示例:

std::cout << std::fixed << std::setprecision(3) << 123.456 << '\n'; // 123.456
std::cout << std::scientific << std::setprecision(3) << 123.456 << '\n'; // 1.235e+002

若未指定 fixed/scientific,精度指有效数字位数:

std::cout << std::setprecision(3) << 123.456 << '\n'; // 123

使用 showpoint 强制显示小数点:

std::cout << std::showpoint << std::setprecision(3) << 123.456 << '\n'; // 123.

宽度、填充字符与对齐

默认输出时数字周围不留空格。可通过设置字段宽度并指定对齐方式实现左/右/内部对齐。

分组标志含义
std::ios::adjustfieldstd::ios::internal符号左对齐,数值右对齐
std::ios::left整体左对齐
std::ios::right整体右对齐(默认)
操控符含义
std::internal / std::left / std::right切换对齐方式
std::setfill(char)设置填充字符(位于 <iomanip>
std::setw(int)设置字段宽度(位于 <iomanip>

示例:

std::cout << std::setw(10) << -12345 << '\n';         // 默认右对齐
std::cout << std::setw(10) << std::left << -12345 << '\n'; // 左对齐
std::cout << std::setw(10) << std::internal << -12345 << '\n'; // 内部对齐

输出:

    -12345
-12345    
-    12345

注意:setw()width() 仅影响下一次输出,不具持久性。

设置填充字符:

std::cout.fill('*');
std::cout << std::setw(10) << std::left << -12345 << '\n'; // -12345****

ostream 及整个 <iostream> 库还包含更多输出函数、标志与操控符,视需求可进一步查阅标准库文档。

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"