在C语言中,我们一般用printf()函数来进行输出,通过输出字符串中的格式说明符(如%4.2d)可以很容易地格式化输出。而在C++中,为简便起见,往往不指定输出的格式,由系统根据数据的类型采取默认的格式,但有时也需要数据按我们指定的格式输出,比如以十六进制的形式输出一个整数等。有两种方法可以达到格式化输出的目的,一种是使用流对象的有关成员函数,还有一种是使用控制符方法,这两种方法殊途同归,它们的原理和起到的作用都是一样的,只不过使用形式不一样。
表1 用于控输出格式的流成员函数及控制符
流成员函数 | 作用相同的控制符 | 作用 |
---|---|---|
precision(n) | setprecision(n) | 设置实数的精度为n位 |
width(n) | setw(n) | 设置字段宽度为n位 |
fill(c) | setfill(c) | 设置填充宇符c |
setf(ios::state) | setiosflags(ios::state) | 设置输出格式状态,括号中应给出格式状态,内容与控制符setiosflags括号中的内容相同,如表2所示 |
unsetf(ios::state) | resetioflags(ios::state) | 终止已设置的输出格式状态,在括号中应指定内容 |
表2 设置格式状态的格式标志
格式标志 | 作用 |
---|---|
ios::left | 输出数据在本域宽范围内向左对齐 |
ios::right | 输出数据在本域宽范围内向右对齐 |
ios::internal | 数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充 |
ios::dec | 设置整数的基数为10 |
ios::oct | 设置整数的基数为8 |
ios::hex | 设置整数的基数为16 |
ios::showbase | 强制输出整数的基数(八进制数以0打头,十六进制数以0x打头) |
ios::showpoint | 强制输出浮点数的小点和尾数0 |
ios::uppercase | 在以科学记数法格式E和以十六进制输出字母时以大写表示 |
ios::showpos | 对正数显示“+”号 |
ios::scientific | 浮点数以科学记数法格式输出 |
ios::fixed | 浮点数以定点格式(小数形式)输出 |
ios::boolalpha | 以“true”/“false”的形式输出布尔值 |
ios::unitbuf | 每次输出之后刷新所有的流 |
ios::stdio | 每次输出之后清除stdout, stderr |
我们可以使用用流对象的成员函数来控制输出格式。比如我们想要以十六进制来输出一个整形,设置字段宽度为8位,并用’*’来填充空白的话,可以使用以下代码:
#include
using namespace std;
int main(){
int a = 31;
cout.width(8);
cout.fill('*');
cout.unsetf(ios::dec);
cout.setf(ios::hex);
cout << a << endl;
}
输出为:
******1f
我们也可以使用控制符来控制输出格式,这样就无需调用流的成员函数,可以直接在输出输入流中调用相关控制符,我们可以用以下代码实现上文中同样的输出格式:
#include
#include //不要忘记包含此头文件
using namespace std;
int main(){
int a = 31;
cout << setw(8) << setfill('*') << resetiosflags(ios::dec) << setiosflags(ios::hex) << a << endl;
}
注意:
<
iomanip>。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,
_S_ios_fmtflags_max = __INT_MAX__,
_S_ios_fmtflags_min = ~__INT_MAX__
};
在上述两种方法中,要设置格式标志位都需要调用函数(setf和setiosflags),比较麻烦,所幸C++还有一组关于格式标志的函数,可以直接在输入输出流中使用,比如要实现之前的输出格式我们可以这么写:
#include
#include
using namespace std;
int main(){
int a = 31;
cout << setw(8) << setfill('*') << hex << a << endl;
}
上面的hex就是这样的一个函数,除了hex,表2中的所有格式标志都通过这种方法设置,如果要终止只需标志名前加个“no”就可以,比如showpos和noshowpos(表2中前六项没有no版本)。
另外可以注意到,这里用hex设置十六进制的时候并不用像之前一样先终止十进制,这是为什么呢?先来看看hex的函数定义:
inline ios_base&
hex(ios_base& __base)
{
__base.setf(ios_base::hex, ios_base::basefield);
return __base;
}
可以看到hex其实是调用了setf函数,但这里的setf跟我们上面用到的setf函数不同,这是重载之后有两个形参的setf函数,其定义如下:
fmtflags
setf(fmtflags __fmtfl, fmtflags __mask)
{
fmtflags __old = _M_flags;
_M_flags &= ~__mask;
_M_flags |= (__fmtfl & __mask);
return __old;
}
可以看到这里setf先将mask所对应的位都置0,再将要设置的位置1。具体到hex函数,它是将_S_basefield(_S_dec | _S_oct | _S_hex)都先置0,再将_S_hex位置1。有了这个setf函数,我们在使用hex的时候就不需要先终止dec了,可以直接使用hex。