Seekg 的行为不符合预期


#include <string>
#include <iostream>
int main() {
std::string str;
char magic[9];
std::cin.read((char *)magic, sizeof(magic));
std::cin.seekg(0, std::ios::beg);
while (std::cin >> str) {
std::cout << str << std::endl;
}
}

我的代码包含 std::cin 上的 seekg(0) 函数的实现 它在某些文件上的行为不符合预期 运行时为./a.out < filename

那些没有按预期运行的文件具有字符数(包括尾行字符和其他空格)小于 9 的属性(9 是我们在 seekg 之前从 CIN 读取的字符数)

如果文件包含超过 9 个字符,则其行为符合预期 例如:

123456789

将输出为

123456789

而包含少于 9 个字符的文件不会给出输出

例如:

1234

将不提供输出

对于少于九个字符的文件,您已经尝试用初始read阅读末尾。这意味着已经为流设置了eof(文件末尾)和fail标志,虽然seekg可以重置eof,但它不会重置fail(a)。

您可以通过插入以下内容来检查:

cout << "eof/fail=" << cin.eof() << '/' << cin.fail() << 'n';

紧接在seekg之前和之后.对于分别为 8、9 和 10 的文件大小,您将获得:

eof/fail=1/1
eof/fail=0/1
eof/fail=0/0
eof/fail=0/0
12345678
eof/fail=0/0
eof/fail=0/0
123456789

您可以看到第一次失败导致没有输出,因为fail位仍在设置中。第二个和第三个有输出,因为它从未设置过(输出是显示的字符加上一个换行符)。

要解决此问题,您只需在seekg之前插入以下内容即可清除fail位:

std::cin.clear();

然后在八个字符的文件上运行该代码得到:

eof/fail=1/1
eof/fail=0/0
1234567

表明clear确实清除了fail位。


您可能还需要记住,流不是可搜索性的要求,特别是如果它只是通过标准输入传入。您可能会发现,对于某些大小的文件,如果您已经阅读了流的一大块,则无法回购任意数量的文件。


(a)对于我们中间的语言律师来说,Unformatted input functions(C++11 27.7.2.3/41C++14 27.7.2.3/41C++17 30.7.4.3/41)对seekg如何运作都有基本相同的文本(我的强调):

构造一个哨兵对象后,如果 fail() != true,则执行...

最新更新