C++ Primer中有这样一段代码:
int main()
{
int sum = 0, val = 0;
while(cin >> val)
sum += val;
cout << "sum:" << sum << endl;
return 0;
}
这里解释下 while的判断条件 cin >> val
cin本身是一个istream对象,该对象重载了 operator >>,返回istream& 对象,而 while 语句中的条件表达式的
返回值应该是bool 类型、整数类型或其他和整数类型兼容的类型,istream & 显然和整数类型不兼容,为什么
while(cin>>n)还能成立呢?这是因为,istream 类对强制类型转换运算符 bool 进行了重载,这使得 cin 对象可以
被自动转换成 bool 类型。所谓自动转换的过程,就是调用 cin 的 operator bool() 这个成员函数,而该成员函数
可以返回某个标志值,该标志值在 cin 没有读到输入结尾时为 true,读到输入结尾后变为 false。对该标志值的设置,
在 operator <<() 成员函数中进行。
当我们从键盘输入字符串的时候需要敲一下回车键才能够将这个字符串送入到缓冲区中,那么敲入的这个回车键(\r)会
被转换为一个换行符\n,这个换行符\n也会被存储在cin的缓冲区中并且被当成一个字符来计算!比如我们在键盘上敲下
了123456这个字符串,然后敲一下回车键(\r)将这个字符串送入了缓冲区中,那么此时缓冲区中的字节个数是7 ,而
不是6。
cin读取数据也是从缓冲区中获取数据,缓冲区为空时,cin的成员函数会阻塞等待数据的到来,一旦缓冲区中有数据,
就触发cin的成员函数去读取数据。当cin>>从缓冲区中读取数据时,若缓冲区中第一个字符是空格、tab或换行这些
分隔符时,cin>>会将其忽略并清除,继续读取下一个字符,若缓冲区为空,则继续等待。但是如果读取成功,字符后
面的分隔符是残留在缓冲区的,cin>>不做处理。
使用一个istream的对象作为条件时,效果是检查流的状态。若流有效,则检测成功,返回true。当遇到文件结束符
或者无效的输入(比如用一个字符来作为一个整型数的输入时),istream的对象状态会变为无效。
总而言之:
(1) 输入数据时需要敲回车键才能将数据送到缓存器,cin才能读取缓存区的数据。
(2) 当cin遇到文件结束符(windows中为:ctrl +Z , Unix 中为:ctrl +D),或无效输入才能使cin状态无效。
(3) cin读取数据时,比如当前缓冲区里是2 33 5\n ctrl+D 先读取到2,然后是空格,这时候读取返回,cin仍
然有效,while条件触发成功一次,val此时赋予2,sum += 2 = 2。然后cin读空格之后的33,直到再次遇到空格,
以此类推。最终读到ctro+D,使cin无效,变退出while循环了。
简单的说:cin接收输入时,operator >>() 是会过滤掉不可见字符(如 空格 回车,TAB 等);从第一个非空白符开始读,直到
空白符或文件结束为止,这时候cin>>(也就是cin.operator >>())返回。
贴一个网上对 cin >> 底层分析的文章,讲解的非常好: 传送门
结合传送门的文章理解几个state:
1. badbit表示发生系统级的错误,如不可恢复的读写错误。通常情况下一旦badbit被置位,流就无法再使用了。
2. failbit 表示发生可恢复的错误,如期望读取一个数值,却读出一个字符等错误。这种问题通常是可以修改的,
流还可以继续使用。
3. 当到达文件的结束位置时,eofbit 和 failbit 都会被置位。
4. goodbit 被置位表示流未发生错误。如果badbit failbit 和eofbit 任何一个被置位,则检查流状态的条件
会失败。
对应的bad(), fail(), eof(), good()能检查对应位是否被置位,返回1表示被置位。但是,badbit被置位时,
fail()也会返回1。
所以使用good()和fail()是确定流能否使用的正确方法。。实际上,流当做条件使用的代码就等价于!fail()。
而且eof() 和bad() 操作只能表示特定的错误。