统计

  • 随笔 - 50
  • 文章 - 42
  • 评论 - 147
  • 引用 - 0

留言簿(6)

随笔分类

文章分类

Link

搜索

  •  

积分与排名

  • 积分 - 162617
  • 排名 - 161

最新评论

阅读排行榜

评论排行榜

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 值的操作将用 truefalse 进行显示。

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

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

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

指定整型值的基数

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

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 函数量重载的,可以用 floatdoublelong double 实参调用,它返回实参的平方根。


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

控制记数法

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


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

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

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

恢复浮点值的默认记数法

与其他操纵符不同,不存在将流恢复为根据被显示值选择记数法的默认状态的操纵符,相反,我们必须调用 unsetf 成员来取消 scientificfixed 所做的改变。要将流恢复为浮点值的默认处理,将名为 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 等)的序列处理。

posted on 2009-05-27 17:53 pear_li 阅读(1250) 评论(0)  编辑 收藏 引用 所属分类: C++


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理