14.4.5 flag函数读取和设定格式状态字
ios_base类中提供了成员函数flag来读取和设置格式状态字,flag函数有两种调用形式,如下所示。
❑long flags()。
❑long flags(long flagNew)。
1.long flags()
无参的flags函数调用返回当前格式状态字的情况,而不对其做任何的改变,如以下示例代码14.8所示。
代码14.8 无参flags函数的调用FlagsSample1
<————————————文件名:example1408.cpp———————————————> 01 #include<iostream> 02 using namespace std; 03 int main() 04 { 05 cout<<cout. flags()<<endl; 06 return 0; 07 }
输出结果如下所示。
513
【代码解析】代码的用法很简单,第5行的flags函数是ios_base类的公有成员函数,而cout所属的ostream类是从ios_base类间接派生而来的,因此,可以用派生类的对象cout调用flags函数,返回结果为513,这是系统默认的十进制形式,其对应的二进制形式如下所示。
0000 0000 0000 0000 0000 0010 0000 0001
等价于ios_base:skipws|ios_base:dec,这和C++默认的输入输出状态字是一致的。
2.long flags(long flagNew)
这种调用方式将flagNew以位方式复制到格式状态字中,这样实现了对格式状态位的操作,返回修改前的格式状态字。
可以自行计算参数flagNew应设定的值,举例来说,要使得格式化常量showpos、showbase、oct和right对应的位为1,而其他位都设为0,可以将其分别对应的值0x0020、0x0008、0x0400和0x0080加起来,产生程序使用的值0x04A8,如下所示。
cout.flags(0x40A8);使用这种方法会给程序的可移植性带来问题,因为不同的C++编译工具和实现中格式化常量的具体值可能不同,所以推荐的用法是使用位与或位或命令。举例来说,要在当前格式状态字的基础上使showpos有效(对应位设为1),可使用下列语句。 cout.flags(cout.flags()|ios_base:showpos);通过位或指令,将状态控制字中相应位置设为1。同理,如果要使某项无效,可以用位与的方式,比如要使得showbase无效(对应位设为0),如下所示。 cout.flags(cout.flags()&~ios_base:showbase);
对showbase取反后,则除其对应位变为0外,其余位都为1,此时再和cout.flag()返回的当前格式状态字位与,则格式状态字中showbase对应位被成功设置0。
如示例代码14.9所示。
代码14.9 有参flags函数的用法FlagsSample2
<———————————-文件名:example1409.cpp———————————————-> 01 #include<iostream> 02 using namespace std; 03 int main() 04 { 05 int x=255; 06 cout<<x<<endl; 07 cout. flags(cout.flags()&~ios_base:dec);//位与抵消掉某个选项 08 cout. flags(cout.flags()|ios_base:hex);//位或添加某个选项 09 cout<<x<<endl; 10 return 0; 11 }
输出结果如下所示。
255 ff
【代码解析】代码第8行通过“cout.flags(cout.flags()|ios_base:hex);”以位或的方式将输出转换为十六进制,但细心的读者可能会注意到此前的第7行语句“cout.flags(cout.flags()&~ios_base:dec);”,其作用是使系统默认的十进制输出失效,这不难理解,在某个时刻,八进制、十进制和十六进制3种形式至多只能有1个有效,否则是会出现问题,像hex、oct和dec等成并列关系的格式化常量还有另外两组,分别是“right、left和internal”以及“scientific和fixed”。
为方便编程,提高效率,ios_base类中同样定义了格式化常量adjustfield、basefield和floatfield,其取值分别如下所示。
adjustfield=0x01c0,//0000 0001 1100 0000 basefield=0x0e00,//0000 1110 0000 0000 floatfield=0x3000,//0011 0000 0000 0000从上述取值中不难看出以下内容。 adjustfield实际上等价于right|left|internal basefield实际上等价于dec|oct|hex floatfield实际上等价于scientific|fixed引入这3个常量后,省去了判断当前状态的麻烦,代码14.9比较简单,在设定十六进制前,确切知道系统当前格式状态字中dec有效(即默认为十进制),可如果程序结构相对复杂,或格式状态字已被设置多次,程序员不确定此时的状态控制字中到底是dec有效还是oct有效,因此需要加以判断,使用上述定义的3个格式化常量后,不再需要判断,仍以代码14.9为例,代码如下所示。 cout.flags(cout.flags()&~ios_base:basefield);
一次性将dec、oct和hex对应的位都设置为0,而后再根据需要对hex进行设置即可,其他的两个格式化常量adjustfield(对齐方式相关)和floatfield(浮点数显示相关)的用法与此一致。