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;
        }
    }

мой код содержит реализацию функции seekg(0) для std::cin, он ведет себя не так, как ожидалось, в некоторых файлах при запуске как ./a.out < filename

те файлы, которые ведут себя не так, как ожидалось, имеют свойство, состоящее в том, что они имеют количество символов (включая символы конца строки и другие пробелы) меньше 9 (9 — это количество символов, которое мы читаем из cin перед seekg)

если файл содержит более 9 символов, он ведет себя так, как ожидалось, например:

123456789

выдаст вывод как

123456789

в то время как файл, содержащий менее 9 символов, не будет выводить

Например:

1234

не даст выхода


person srbcheema1    schedule 26.02.2018    source источник
comment
возможно, связано: stackoverflow .com/questions/11765718/   -  person kmdreko    schedule 26.02.2018
comment
Вероятно, вы обнаружите, что поиск терпит неудачу. Проверьте cin.fail(). В более общем смысле, успех cin.seek() не гарантируется, так как не гарантируется поддержка произвольного доступа (что и происходит при поиске). Если cin читает напрямую с клавиатуры (что является типичным значением по умолчанию), поиск завершится ошибкой. Практически это МОЖЕТ работать, если cin перенаправляется в реальный файл.   -  person Peter    schedule 26.02.2018


Ответы (1)


С файлом менее девяти символов вы уже пытались читать дальше конца с вашим начальным 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 все еще установлен. Второй и третий имеют выходные данные, потому что они никогда не устанавливались (вывод — это показанные символы плюс одна новая строка).

Чтобы исправить это, вы можете очистить бит fail, просто вставив следующее перед вашим seekg:

std::cin.clear();

Затем запуск этого кода в восьмисимвольном файле дает:

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

показывая, что clear действительно очистил бит fail.


Вы также можете иметь в виду, что необходимо, чтобы поток был доступным для поиска, особенно если он просто поступает через стандартный ввод. Вы можете обнаружить, что для файлов определенного размера вы не можете найти произвольное количество, если вы прочитали большой кусок потока.


(a) Для языковых юристов среди нас Unformatted input functions (C++11 27.7.2.3/41, C++14 27.7.2.3/41 и C++17 30.7.4.3/41) есть практически один и тот же текст о том, как работает seekg (выделено мной):

После создания сторожевого объекта if fail() != true, выполняется...

person paxdiablo    schedule 26.02.2018