分类: C/C++
2016-08-15 22:22:34
原文地址: C++格式化输入输出 作者:welkin
格式标记位的取值为0或1:0表示关闭(不使用此格式),1表示开启(使用此格式)。
15个标记位的含义可参考下面三张表:
标记位 |
含义 |
boolalpha | 如开启,则输入和输出使用bool值(即Ture或False) |
showbase | 如开启,则对于输出,使用C++ 基数前缀(0,0x) |
showpoint | 如开启,则显示末尾的小数点 |
uppercase | 如开启,则对于16进制,使用大写字母;对于10进制,使用E表示法 |
showpos | 如开启,则在正数前面加上+ |
标记位 |
含义 |
dec | 如开启,则使用基数10(进行输出) |
oct | 如开启,则使用基数8 |
hex | 如开启,则使用基数16 |
fixed | 如开启,则使用定点计数法 |
scientific | 如开启,则使用科学计数法 |
left | 如开启,则使用左对齐 |
right | 如开启,则使用右对齐 |
internal | 如开启,则符号或基数前缀左对齐,值右对齐 |
标记位 |
含义 |
skipws | 如开启,则跳过输入流中的空白字符 |
unitbuf | 如开启,则每次输出操作后都会清空缓冲区 |
先来看一个简单的程序:
#include
using namespace std;
int main()
{
int x;
x = cout.setf(ios::showpos);
cout << x << endl;
x = cout.setf(ios::uppercase);
cout << x << endl;
system("pause");
return 0;
}
输出结果是:
setf()函数用于设置格式标记,函数接受一个设格式常量作为参数,在设置成功之后函数会返回一个值,该值指出了所有15个标记的上一次设置情况。
但将这个返回值进行输出,并不是每一个标记位的bit值,而是一个整数,为什么?
实际上,这15个bit值视为一个整体,从而组成一个二进制数,并能够转化为十进制数。
这15个标记位的排列顺序是:
uppercase | unitbuf | skipws | showpos | showpoint | showbase | scientific | right | oct | left | internal | hex | fixed | dec | boolalpha |
比如,setf()函数第一次的返回值是4098,这个值实际上是输出格式的初始状态,转化二进制为001000000000010,那么格式状态为:
uppercase | unitbuf | skipws | showpos | showpoint | showbase | scientific | right | oct | left | internal | hex | fixed | dec | boolalpha |
0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
而6146转化为二进制001100000000010,这一次的值反映的是开启了showpos位后的格式状态:
uppercase | unitbuf | skipws | showpos | showpoint | showbase | scientific | right | oct | left | internal | hex | fixed | dec | boolalpha |
0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
两次对比,我们可以看出,的确是在初始状态的基础上开启了showpos位。
接着我们来看看格式常量,格式常量一共有18个,其中15个用于打开相应的格式标记为,另外3个做为指示功能用
#include
using namespace std;
int main()
{
cout << "boolalpha " << ios::boolalpha <
cout << "fixed " << ios::fixed << endl;
cout << "hex " <
cout << "left " << ios::left << endl;
cout << "oct " << ios::oct << endl;
cout << "right " << ios::right << endl;
cout << "scientific " << ios::scientific << endl;
cout << "showbase " << ios::showbase <
cout << "unitbuf " << ios::unitbuf << endl;
cout << "uppercase " << ios::uppercase <
cout << endl;
cout << "basefield " << ios::basefield << endl;
cout << "adjustfield " << ios::adjustfield << endl;
cout << "floatfield " << ios::floatfield << endl;
system("pause");
return 0;
}
格式常量 |
十进制值 |
意义 |
ios::boolalpha |
1 |
开启boolalpha标记位,输入和输出使用bool值(即Ture或False) |
ios::showbase |
512 |
开启showbase标记位,对于输出,使用C++ 基数前缀(0,0x) |
ios::showpoint |
1024 |
开启showpoint标记位,显示末尾的小数点 |
ios::uppercase |
16384 |
开启uppercase标记位,对于16进制,使用大写字母;对于10进制,使用E表示法 |
ios::showpos |
2048 |
开启showpos标记位,在正数前面加上+ |
格式常量 |
十进制值 |
意义 |
格式常量 |
十进制值 |
意义 |
ios::basefield |
74 |
指示相关标记位:dec、oct、hex | ios::dec |
2 |
开启dec标记位,使用基数10 |
ios::oct |
64 |
开启oct标记位,使用基数8 | |||
ios::hex |
8 |
开启hex标记位,使用基数16 | |||
ios::floatfield |
260 |
指示相关标记位:fixed、scientific | ios::fixed |
4 |
开启fixed标记位,使用定点计数法 |
ios::scientific |
256 |
开启scientific标记位,使用科学计数法 | |||
ios::adjustfield |
176 |
指示相关标记位:left、right、internal | ios::left |
32 |
开启left标记位,使用左对齐 |
ios::right |
128 |
开启right标记位,使用右对齐 | |||
ios::internal |
16 |
开启internal标记位,符号或基数前缀左对齐,值右对齐 |
注意:这些都是常量,是作为 函数参数 来设置格式状态,而不是格式标记位的存储空间。
15个蓝色的格式常量用来打开对应的格式标记位,如果将其十进制值转化为二进制,再于标记位顺序表比对,就可以看出来。
3个绿色的格式常量用来指示标记位,为什么要指示?比如:dec、oct、hex是不可能同时打开的,而ios::basefield则指示这三个标记位为一组,74=2+64+8,这意味着它转化为二进制的比对情况是dec、oct、hex为1,但它不是设置标记位,而是指示,具体原理在setf()函数中详细解释。
最后来看看setf()函数:
setf()函数有两种原型,一种是fmtflags setf ( fmtflags );
它接收一个参数,该参数是一种 标记类型,提供实参时,可以是整数,该整数转化为二进制后赋给格式状态。但这种方法抽象且不安全。
也可以将格式常量作为实参提供给函数,在这种情况下,setf()函数会打开相应的标记位,且不会影响其它标记位。但这种方法仍不安全。很明显,既打开dec标记位,又打开oct标记位是没有意义的。
另一种原型是fmtflags setf ( fmtflags , fmtflags );
它接收两个 标记类型 的参数。第一个参数指出要打开的标记位,第二个参数则是指示要清除的一批相关位。
比如:cout.setf( ios::hex, ios::basefield ); 这表示使用16进制输出格式。首先,ios::basefield指示出了要清除的标记位,setf()函数将ios::basefield所指示的标记位,即dec、oct、hex全部清零。然后ios::hex使得setf()函数打开hex标记位。这是一种安全的方法,避免了同时打开dec、hex两个标记位等没有实际意义的情况发生。
setf()是如何实现清除的?
ios::basefield转化为二进制000000001001010,这三个1的位置指示的是dec、oct、hex标记位。setf()函数将这个二进制数取反111111110110101,然后与原格式状态标记位进行“与”操作,使得原格式状态的dec、oct、hex标记位为0,而其它标记位不变。(参看《C++ primer plus》683页位操作)
然后setf()函数根据第一个参数ios::hex将格式状态的hex标记位打开,其它标记位不变。至此,格式设置就成功完成了。我们也可以看出,setf()函数不会影响无关标记位的状态。
http://blog.csdn.net/angelcm51/archive/2008/04/26/2330496.aspx