C++ stream格式化输出输入

本文摘自C++primer第四版附录A3
A.3.3. 控制输出格式

许多操纵符使我们能够改变输出的外观。有两大类的输出控制:控制数值的表示,以及控制填充符的数量和布局。

控制布尔值和格式

改变对象格式化状态的操纵符的一个例子是 boolalpha 操纵符。默认情况下,将 bool 值显示为 1 或 0,true 值显示为 1,而 false值显示为 0。可以通过流的 boolalpha 操纵符覆盖这个格式化:

cout << "default bool values: "
          << true << " " << false
          << "\nalpha bool values: "
          << boolalpha
          << true << " " << false
          << endl;

执行时,这段程序产生下面的输出:

default bool values: 1 0
     alpha bool values: true false


一旦将 boolalpha “写”至 cout,从这个点起就改变了 cout 将怎样显示 bool 值,后续显示 bool 值的操作将用 true 或 false 进行显示。

要取消 cout 的格式状态改变,必须应用 noboolalpha

bool bool_val;
cout << boolalpha    // sets internal state of cout
     << bool_val
     << noboolalpha; // resets internal state to default formatting


现在只改变 bool 值的格式化来显示 bool_val,并且立即将流重置为原来的状态。

指定整型值的基数

默认情况下,用十进制读写整型值。通过使用操纵符 hexoct 和 dec,程序员可以将表示进制改为八进制、十六进制或恢复十进制(浮点值的表示不受影响):

const int ival = 15, jval = 1024; // const, so values never change
     cout << "default: ival = " << ival
          << " jval = " << jval << endl;
     cout << "printed in octal: ival = " << oct << ival
          << " jval = " << jval << endl;
     cout << "printed in hexadecimal: ival = " << hex << ival
          << " jval = " << jval << endl;
     cout << "printed in decimal: ival = " << dec << ival
          << " jval = " << jval << endl;


编译和执行的时候,程序产生下面的输出:

default: ival = 15 jval = 1024
     printed in octal: ival = 17 jval = 2000
     printed in hexadecimal: ival = f jval = 400
     printed in decimal: ival = 15 jval = 1024


注意,像 boolalpha 一样,这些操纵符改变格式状态。它们影响紧接在后面的输出,以及所有后续的整型输出,直到通过调用另一操纵符重围格式为止。

指出输出的基数

默认情况下,显示数值的时候,不存在关于所用基数的可见记号。例如,20 是 20,还是 16 的八进制表示?按十进制模式显示数值的时候,会按我们期待的格式打印数值。如果需要打印八进制或十六进制值,可能应该也使用 showbase 操纵符。showbase 操纵符导致输出流使用的约定,与指定整型常量基数所用的相同:

  • 以 0x 为前导表示十六进制。

  • 以 0 为前导表示八进制。

  • 没有任何前导表示十进制。

修改程序使用 showbase 如下:

const int ival = 15, jval = 1024; // const so values never change
     cout << showbase; // show base when printing integral values
     cout << "default: ival = " << ival
          << " jval = " << jval << endl;
     cout << "printed in octal: ival = " << oct << ival
          << " jval = " << jval << endl;
     cout << "printed in hexadecimal: ival = " << hex << ival
          << " jval = " << jval << endl;
     cout << "printed in decimal: ival = " << dec << ival
          << " jval = " << jval << endl;
     cout << noshowbase; // reset state of the stream


修改后的输出使得基础值到底是什么很清楚:

default: ival = 15 jval = 1024
     printed in octal: ival = 017 jval = 02000
     printed in hexadecimal: ival = 0xf jval = 0x400
     printed in decimal: ival = 15 jval = 1024


noshowbase 操纵符重置 cout,以便它不再显示整型值的表示基数。

默认情况下,十六进制值用带小写 x 的小写形式打印。可以应用 uppercase 操纵符显示 X 并将十六进制数字 a - f 显示为大写字母。

cout << uppercase << showbase << hex
          << "printed in hexadecimal: ival = " << ival
          << " jval = " << jval << endl
          << nouppercase << endl;


前面的程序产生下面的输出:

printed in hexadecimal: ival = 0XF jval = 0X400

要恢复小写,就应用 nouppercase 操纵符。

控制浮点值的格式

对于浮点值的格式化,可以控制下面三个方面:

  • 精度:显示多少位数字。

  • 记数法:用小数还是科学记法法显示。

  • 对是整数的浮点值的小数点的处理。

默认情况下,使用六位数字的精度显示浮点值。如果值没有小数部分,则省略小数点。使用小数形式还是科学记数法显示数值取决于被显示的浮点数的值,标准库选择增强数值可读性的格式,非常大和非常小的值使用科学记数法显示,其他值使用小数形式。

指定显示精度

默认情况下,精度控制显示的数字总位数。显示的时候,将浮点值四舍五入到当前精度。因此,如果当前精度是 4,则 3.14159 成为3.142;如果精度是 3,打印为 3.14

通过名为 precision 的成员函数,或者通过使用 setprecision 操纵符,可以改变精度。precision 成员是重载的(第 7.8 节):一个版本接受一个 int 值并将精度设置为那个新值,它返回先前的精度值;另一个版本不接受实参并返回当前精度值。setprecision 操纵符接受一个实参,用来设置精度。

下面的程序说明控制显示浮点值所用精度的不同方法:

// cout.precision reports current precision value
     cout << "Precision: " << cout.precision()
          << ", Value: "   << sqrt(2.0) << endl;
     // cout.precision(12) asks that 12 digits of precision to be printed
     cout.precision(12);
     cout << "Precision: " << cout.precision()
          << ", Value: "   << sqrt(2.0) << endl;
     // alternative way to set precision using setprecision manipulator
     cout << setprecision(3);
     cout << "Precision: " << cout.precision()
          << ", Value: "   << sqrt(2.0) << endl;


编译并执行后,程序产生下面的输出:

Precision: 6, Value: 1.41421
     Precision: 12, Value: 1.41421356237
     Precision: 3, Value: 1.41


这个程序调用标准库中的 sqrt 函数,可以在头文件 cmath 中找到它。sqrt 函数量重载的,可以用 floatdouble 或 long double实参调用,它返回实参的平方根。

 

操纵符和其他接受实参的操纵符定义在头文件 iomanip 中。

控制记数法

默认情况下,用于显示浮点值的记数法取决于数的大小:如果数很大或很小,将按科学记数法显示,否则,使用固定位数的小数。标准库选择使得数容易阅读的记数法。

 

将浮点数显示为普通数(相对于显示货币、百分比,那时我们希望控制值的外观)的时候,通常最好让标准库来选择使用的记数法。要强制科学记数法或固定位数小数的一种情况是在显示表的时候,表中的小数点应该对齐。

如果希望强制科学记数法或固定位数小数表示,可以通过使用适当的操纵符做到这一点:scientific 操纵符将流变为使用科学记数法。像在十六进制值上显示 x 一样,也可以通过 uppercase 操纵符控制科学记数法中的 efixed 操纵符将流为使用固定位数小数表示。

这些操纵符改变流精度的默认含义。执行 scientific 或 fixed 之后,精度值控制小数点之后的数位。默认情况下,精度指定数字的总位数——小数点之前和之后。使用 fixed 或 scientific 命名我们能够按列对齐来显示数,这一策略保证小数点总是在相对于被显示的小数部分固定的位置。

恢复浮点值的默认记数法

与其他操纵符不同,不存在将流恢复为根据被显示值选择记数法的默认状态的操纵符,相反,我们必须调用 unsetf 成员来取消scientific 或 fixed 所做的改变。要将流恢复为浮点值的默认处理,将名为 floatfield 的标准库定义值传给 unsetf 函数:

// reset to default handling for notation
     cout.unsetf(ostream::floatfield);


除了取消它们的效果之外,使用这些操纵符像使用任意其他操纵符一样:

cout << sqrt(2.0) << '\n' << endl;
     cout << "scientific: " << scientific << sqrt(2.0) << '\n'
          << "fixed decimal: " << fixed << sqrt(2.0) << "\n\n";
     cout << uppercase
          << "scientific: " << scientific << sqrt(2.0) << '\n'
          << "fixed decimal: " << fixed << sqrt(2.0) << endl
          << nouppercase;
     // reset to default handling for notation
     cout.unsetf(ostream::floatfield);
     cout << '\n' << sqrt(2.0) << endl;


产生如下输出:

1.41421

     scientific: 1.414214e+00
     fixed decimal: 1.414214

     scientific: 1.414214E+00
     fixed decimal: 1.414214

     1.41421


显示小数点

默认情况下,当浮点值的小数部分为 0 的时候,不显示小数点。showpoint 操纵符强制显示小数点:

cout << 10.0 << endl;        // prints 10
     cout << showpoint << 10.0    // prints 10.0000
          << noshowpoint << endl; // revert to default handling of decimal point

noshowpoint 操纵符恢复默认行为。下一个输出表达式将具有默认行为,即,如果浮点值小数部分为 0,就取消小数点。

填充输出

按栏显示数据的时候,经常很希望很好地控制数据的格式化。标准库提供下面几个操纵帮助我们实现需要的控制:

  • setw,指定下一个数值或字符串的最小间隔。

  • left,左对齐输出。

    right,右对齐输出。输出默认为右对齐。

  • internal,控制负值的符号位置。internal 左对齐符号且右对齐值,用空格填充介于其间的空间。

  • setfill,使我们能够指定填充输出时使用的另一个字符。默认情况下,值是空格。

 

像 endl 一样,setw 不改变输出流的内部状态,它只决定下一个输出的长度。

下面程序段说明了这些操纵符:

int i = -16;
     double d = 3.14159;
     // pad first column to use minimum of 12 positions in the output
     cout << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n';
     // pad first column and left-justify all columns
     cout << left
          << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n'
          << right; // restore normal justification
     // pad first column and right-justify all columns
     cout << right
          << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n';
     // pad first column but put the padding internal to the field
     cout << internal
          << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n';
     // pad first column, using # as the pad character
     cout << setfill('#')
          << "i: " << setw(12) << i << "next col" << '\n'
          << "d: " << setw(12) << d << "next col" << '\n'
          << setfill(' '); // restore normal pad character


执行时,该程序段产生如下输出:

i:          -16next col
     d:      3.14159next col
     i: -16         next col
     d: 3.14159     next col
     i:          -16next col
     d:      3.14159next col
     i: -         16next col
     d:      3.14159next col
     i: -#########16next col
     d: #####3.14159next col


A.3.4. 控制输入格式化

默认情况下,输入操作符忽略空白(空格、制表符、换行符、进纸和回车)。对下面的循环:

while (cin >> ch)
         cout << ch;


给定输入序列

a b   c
     d


循环执行四次从字符 a 读到 d,跳过介于其间的空格、可能的制表符和换行符。该程序段的输出是:

abcd

noskipws 操纵符导致输入操作符读(而不是跳过)空白。要返回默认行为,应用 skipws 操纵符:

cin >> noskipws;      // set cin so that it reads whitespace
     while (cin >> ch)
             cout << ch;
     cin >> skipws; // reset cin to default state so that it discards whitespace


给定与前面相同的输入,该循环进行 7 次迭代,读输入中的空白以及字符。该循环产生如下输出:

a b    c
     d
A.3.5. 未格式化的输入/输出操作

迄今为止,示例程序中只使用过格式化的 IO 操作。输入和输出操作符(<< 和 >>)根据被处理数据的类型格式化所读写的数据。输入操作符忽略空白,输出操作符应用填充、精度等。

标准库还提供了丰富的支持未格式化 IO 的低级操作,这些操作使我们能够将流作为未解释的字节序列处理,而不是作为数据类型(如charintstring 等)的序列处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值