从 istringstream 读取字符时出现意外行为

unexpected behavior when read a character from istringstream

本文关键字:意外 istringstream 读取 字符      更新时间:2023-10-16

我对流行为有疑问,请参阅以下示例。我期待的是ss_char和ss_int将是 eof 状态,但只有ss_int将是 eof 状态。

我的问题是,为什么ss_char不是 eof 状态?我不能使用运算符>>,只能使用 istringstream::get(( 函数,但是为什么要成功读取值呢?

输出:
字符值:A
整数值:42

ss_char eof:假的//为什么是假的?
ss_int eof:真

对不起,我的英语很差。我正在努力提高我的英语水平。

#include <iostream>
#include <sstream>
int main(int /*argc*/, char const * /*argv*/[])
{
    char c;
    int num;
    std::istringstream ss_int("42");
    std::istringstream ss_char("a");
    if (ss_char >> c)
    {
        std::cout << "char value: " << c << std::endl;
    }
    else
    {
        std::cout << "cannot read char" << std::endl;
    }
    if (ss_int >> num)
    {
        std::cout << "int  value: " << num << std::endl;
    }
    else
    {
        std::cout << "cannot read int" << std::endl;
    }
    std::cout << std::endl;
    std::cout << "ss_char eof: " << std::boolalpha << ss_char.eof() << std::endl; // why false
    std::cout << "ss_int  eof: " << std::boolalpha << ss_int.eof() << std::endl;
    return 0;
}

CppReference 说:"此函数仅报告由最近的 I/O 操作设置的流状态,它不检查关联的数据源。例如,如果最近的 I/O 是返回文件最后一个字节的 get((,则 eof(( 返回 false。下一个 get(( 无法读取任何内容并设置 eofbit。只有这样 eof(( 才会返回 true。

当读取操作尝试读取文件末尾以外的内容时,oefbit 将变为 true,但当它精确读取文件末尾而不尝试进一步读取时,oefbit 将变为 true。当你读取字符时,它知道它应该读取一个字节,所以这个读取操作是可以的,读取位置前进 1 个字节,走到最后,但假设流仍然没有注意到它确实是结束,如果你尝试读取其他内容,它会。当你读取一个整数时,它会尝试读取超过 42 的读数,因为整数的长度不清楚,它可能是 42901,所以它必须读取直到它看到一个空格和行尾,或者最终看到文件/流的末尾,如果没有其他东西要读取。

运算符>>的结果是流本身。当它转换为 void*(或 bool,取决于 c++11 或更早版本(时,它以 !fail(( 的形式工作,因此它会告诉您读取或写入操作是否正常,无论它是否到达文件末尾(如果下一个读取操作现在在末尾,它将失败(。

在您尝试读取的末尾之前,EOF 条件实际上不会发生。

char情况下,您只读取一个字符,唯一可用的字符。你不要试图读到最后,因为没有必要。

另一方面,提取int会尝试使用尽可能多的数字。 它读取 4 和 2,然后尝试再次读取以查看是否有另一个数字要消耗,在这种情况下,它确实尝试读取末尾。 它注意到输入结束了,因此完成了 42 的转换。

提取字符时,它将一次拉取一个字符,并在连续调用时跳过空格。

提取 int 时,解析器会尝试提取尽可能多的字符以形成数字。 这会导致整数提取在测试用例中命中 EOF。