一般情况下,程序中输入或输出信息都是使用默认的格式。但是我们也可以用 ios 的成员函数或者是使用“操控符” 来精确控制 I/O 数据格式。
每个流都有一组格式标志位来控制信息的格式。在类 ios 中定义了一个位掩码枚举类型 fmtflags ,这些枚举值定义在 ios 的基类 -- 类 ios_base 中。比如在 linux 中,这个值定义在 /usr/include/c++/4.4.3/bits/ios_base.h 中,且定义如下:
[C++] 纯文本查看 复制代码 enum _Ios_Fmtflags
{
_S_boolalpha = 1L << 0,
_S_dec = 1L << 1,
_S_fixed = 1L << 2,
_S_hex = 1L << 3,
_S_internal = 1L << 4,
_S_left = 1L << 5,
_S_oct = 1L << 6,
_S_right = 1L << 7,
_S_scientific = 1L << 8,
_S_showbase = 1L << 9,
_S_showpoint = 1L << 10,
_S_showpos = 1L << 11,
_S_skipws = 1L << 12,
_S_unitbuf = 1L << 13,
_S_uppercase = 1L << 14,
_S_adjustfield = _S_left | _S_right | _S_internal,
_S_basefield = _S_dec | _S_oct | _S_hex,
_S_floatfield = _S_scientific | _S_fixed,
_S_ios_fmtflags_end = 1L << 16
};
我们就使用这些枚举值来设置或清除格式标志位。
当 skipws 被设置时,在从流输入的时候,开头的空白字符(包括空格符、制表符以及换行符)将被忽略;当标志被清除时,则不会忽略这些字符。
当 left 标志位被设置时,输出格式左对齐。当 right 被设置时,输出格式右对齐。
当 internal 被设置时,如果输出的是一个数值,那么数值的数字字符之间将用空格填充以进行对齐。如果这些标志位都没有被设置,那么默认情况下使用右对齐。
默认情况下,数值以十进制形式输出。如果设置 oct ,那么数值将以八进制形式输出。如果设置 hex ,那么数值将以十六进制形式输出。如果要重新使用默认值,那么可以设置标志位 dec 。
如果设置了 showbase,那么在输出数值的同时还输出数值的基数。例如,如果是指的基数是十六进制,那么数值 1F 将输出为 0x1F 。
在显示数值的科学计数法时,字母 e 是小写的。同样,在输出十六进制时,字符 x 也是小写的。当标志位 uppercase 被设置时,这些符号将以大写格式输出。
如果设置 showpos ,那么在输出正数时会再数值前面附加加号。
如果设置 showpoint ,那么在输出浮点数时,将会输出小数点和末尾的 0,无论是否需要。
如果设置了 scientific ,那么浮点数将以科学计数法格式输出。
如果设置了 fixed,那么浮点数将以普通格式输出。如果这两个标志都没有设置,那么编译器自动选择合适的格式输出浮点数。
如果设置了 unitbuf,那么在每次插入操作完成后,缓冲区中的内容将被刷新。
如果设置了 boolalpha ,那么布尔值将使用关键字 true 或 false 进行输入输出。
我们使用函数 setf() 来设置标志位,改函数是 ios 的成员函数,其通用形式如下:fmtflags setf(fmtflags flags); 改函数将返回流以前的格式标志位,并将 flags 指定的标志位设为流当前的输出格式标志位。比如如果想设置 showbase 标志位,那么可使用下面语句:stream.setf(ios::showbase) 其中,stream 表示需要设置标志位的流对象。这里使用了 ios:: 来指定 showbase 所在的作用域。因为 showbase 是在类 ios 中定义的枚举常量值,所以在使用它的时候必须在前面加上 ios 来限定它的作用域。
下面程序演示了使用 setf() 来设置 showpos 和 scientific 标志的情况:
[C++] 纯文本查看 复制代码 #include <iostream>
using namespace std;
int main()
{
cout.setf(ios::showpos);
cout.setf(ios::scientific);
cout << 123 << " " << 123.23 << endl;
return 0;
}
运行输出:./setf
+123 +1.232300e+02 如果需要同时设置多个标志位,那么可使用 OR 将这些标志位连接起来,比如:cout.setf(ios::scientific | ios::showpos);
相对应的,可以使用 unsetf() 函数来清除标志位,其原型如下:void unsetf(fmtflags flags); 其中,flags 指定的标志位将被清除(对其他的标志位没有影响)。
又是我们需要的只是流当前的标志位,在这种情况下,可以使用函数 flags() ,函数原型如下:该函数将返回流的当前标志位。
下面演示了 flags() 和 unsetf() 函数的用法:
[C++] 纯文本查看 复制代码 #include <iostream>
using namespace std;
void showflags(ios::fmtflags f);
int main()
{
ios::fmtflags f;
f = cout.flags();
showflags(f);
cout.setf(ios::showpos);
cout.setf(ios::scientific);
f = cout.flags();
showflags(f);
cout.unsetf(ios::scientific);
f = cout.flags();
showflags(f);
return 0;
}
void showflags(ios::fmtflags f)
{
long i;
for (i = 0x4000; i; i = i >> 1)
if (i & f) cout << "1 ";
else cout << "0 ";
cout << "\n";
}
运行输出:./unsetflags
0 0 1 0 0 0 0 0 0 0 0 0 0 1 0
0 0 1 1 0 0 1 0 0 0 0 0 0 1 0
0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 编译器不同,上面程序的输出结果也可能不同。 |