C++笔记——io流条件状态

来源:互联网 发布:网络运营主管招聘 编辑:程序博客网 时间:2024/05/29 08:08
io流的条件状态(iostate)一共有4种:
eofbit  已到达文件尾
failbit  非致命的输入/输出错误,可挽回
badbit  致命的输入/输出错误,无法挽回
goodbit  正常,可继续使用

C++ Primer中并没有从本质上去讲这个东西到底是什么,并不好理解,作者认为应该以以下角度去理解io流的条件状态(以下仅代表作者个人的理解,并未查证其真实性)

在istream或ostream类中,可能存在这么一个变量,它包含3个二进制位,这个变量表示一个stream对象所处于的状态,可以想象成3个开关,但是4个状态为什么只用3个二进制位呢?那是因为第4个开关goodbit实则完全取决于前3个开关,前3个开关只要有一个打开,则说明io流已经出错,第4个开关必须关闭,由此,goodbit实际传达的意思是前3个状态都是关闭状态这一信息,而并不是真正存在goodbit这么一个开关。所以这四种状态可以用这3个二进制数来表示(4个常量,不要错误的认为是变量,下文中使用这四个词的时候,有时候是表示这个常量的值,有时候表示这个状态所对应的在io条件状态变量中的二进制位置,根据上下文而定):
eofbit:001
failbit:010
badbit:100
goodbit:000

此处还需要注意的一个点是,这三个开关并不是互斥的,也就是可以同时打开或打开其中的任意两个(从逻辑上不一定符合,比如eofbit和badbit不可能同时发生,但是是可以人为这么设置的)

每次使用cin或者cout,系统根据结果,设置这个变量中的3个二进制位的值。

根据以上,就可以很好的理解io流条件状态涉及到的几个函数了:
rdstate():获取保存当前状态的那个变量的值

eof():判断存储状态的变量中eofbit那个二进制位是否=1(不论其他位的值)
fail():判断存储状态的变量中failbit那个二进制位是否=1(不论其他位的值)
bad():判断存储状态的变量badbit那个二进制位是否=1(不论其他位的值)
good():判断存储状态的变量eofbit、failbit、badbit的二进制位是否全部为0

setstate()和clear():
在讲这两个函数前,必须先论述两个概念:复位和置位。
如果单拿出来一个,从字面意思上来理解,复位是把一个开关拨回到初始时候的位置,而置位是把一个开关根据用户的想法置于关闭或者开启的位置,但是这样理解是完全错误的。。。作者作为一个小白在这个概念上也是纠结的好久才想明白是怎么回事。。。

复位,实则就是关闭;而置位,实则就是开启。

setstate()的作用是置位,也就是开启3个状态中的1个或者几个,需要传入一个iostate值,然后将传入值中的3个二进制位中为1的位置识别,将原io流条件状态变量中的对应位置设置为1,其他位置不变,说白了就是用状态变量 |= 传入的变量。(这里要有二进制计算的基础)。

而clear()的作用则是复位,与setstate形式相同,作用相反,它的本质是用状态变量 &= 传入的变量,把传入的变量中为0的位置在原条件变量中也设置为0,其他位置不变。

举个C++ Primer书上的例子:(作者也是因为一下子想不明白这个例子才进行深入的思考)
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit),书上的解释是复位failbit和badbit,保持其他标志位不变

作者一开始想不明白的点在于clear这个函数既然已经指定了关闭这个操作,那么括号中的参数应该是指定要关闭哪几个位置,但是参数却直接给出了最终要设置到的状态,那么直接用 io条件状态变量 = cin.rdstate() & ~cin.failbit & ~cin.badbit进行直接赋值可好?况且还有一个setstate()函数,如果参数已经给的这么详细,那么clear()和setstate()做的事情不应该是完全一样嘛——将io状态条件变量设置成传入的参数那样。然而我们不能钻这个牛角尖。。。它就是这样,当初的设计者心中的逻辑应该是必须将打开和关闭分开,用|=和&=这两个运算符来区分打开和关闭操作。

那么这条语句就很清晰了,在参数中传入一个变量,将原io条件状态变量中要关闭的二进制位,在传入的这个变量中的对应位置设为0,语句中以原io条件状态变量为标准,将其failbit和badbit这两个位置设为0,其他不管,则得到了一个符合条件的传入参数。(注:这里面还有一个容易迷惑人的地方,那就是failbit和badbit不是变量,而是一个常量,固定表示 010 和 100 ,不要因为是用cin.引出来的,就错误的认为是cin的属性)。

这里就不免要吐槽一下。。这个操作就好像开灯和关灯非得要用两只手,开灯必须用左手开,关灯要用右手关,setstate和clear的本质区别是其内部到底用|=还是用&=,其实是可以用一个函数解决的事情,可能C++的设计者觉得这样在逻辑上更合理,所以使用了这样一种开关灯用不同手的模式。不过也正是这种模式,才有了下面一个用起来很方便的函数:
clear的()重载版本,它不需要传入参数,作用是复位全部3个二进制位,相当于状态变量 &= 000。

本文内容主要来自于作者在阅读C++ Primer时候的一些心得和体会,部分参考网上的一些说法,未经过严格的验证,欢迎批评指正!
原创粉丝点击