Почему не работает символ EOF, если он помещен в конец строки?

Я изучаю С++ и пытаюсь понять, почему символ EOF (Ctrl + Z в Windows) не разбивает цикл while, если он помещен в конец строки.

Мой код:

int main() {
    char ch;
    while(cin >> ch) {
        cout << ch;
    }
}

Когда я вхожу в ^ Z, цикл прерывается. Но когда я вхожу в 12 ^ Z, это не так. Почему?

Ответ 1

Стандарты C и С++ позволяют текстовым потокам делать совершенно нечестивые вещи в текстовом режиме , который по умолчанию. Эти нечестивые вещи включают перевод между внутренними маркерами новой строки и внешними символами управления новой строкой, а также обработку определенных символов или последовательностей символов, обозначающих конец файла. В Unix-land это не сделано, но в Windows-land это делается, поэтому код может относиться только к оригинальным соглашениям Unix-land.

Это означает, что в Windows нет возможности написать переносимую программу C или С++, которая будет скопировать его вход точно на его вход.

Пока в Unix-land, это не проблема вообще.

В Windows строка, состоящая из одного [Ctrl Z], по умолчанию обозначает маркер конца файла. Это происходит не только в консоли, но и в текстовых файлах (в зависимости от инструментов). Windows унаследовала это от DOS, которая, в свою очередь, унаследовала общую идею от CP/M.

Я не уверен, где CP/M получил это, но это только похоже, совсем не то же самое!, как Unix '[Ctrl D].

В Unix-land общее соглашение для конца файла - это просто "больше данных". В консоли [Ctrl D] по умолчанию отправит ваш напечатанный текст немедленно в ожидающую программу. Когда вы еще ничего не набрали на линии, отправляются 0 байт, а чтение, которое возвращает 0 байт, имеет условное обнаружение конца файла.

Основное различие заключается в том, что внутри Windows текстовый конец маркера файла - это данные, которые могут встречаться внутри файла, а внутри Unix - отсутствие данных, которые не могут встречаться в файле. Конечно, Windows также поддерживает обычный конец файла (не более данных!) Для текста. Что усложняет вещи – Windows просто сложнее.


#include <iostream>
using namespace std;

int main()
{
    char ch;
    while(cin >> ch) {
        cout << 0+ch << " '" << ch << "'" << endl;
    }
}

Ответ 2

Вы не найдете ответа на свой вопрос в стандарте С++.

cin >> ch будет "истинным" условием, если не существует условия конца файла или ошибки ввода. Как запускается условие конца файла, язык не указывается, и он может и будет варьироваться от одной операционной системы к другой и даже с параметрами конфигурации в той же ОС. (Например, Unix-подобные системы используют control-D по умолчанию, но это может быть изменено командой stty.)

Windows использует Control-Z для запуска условия конца файла для потока ввода текста; это просто не так, как в начале строки.

Unix ведет себя по-другому; он использует Control-D (по умолчанию) в начале строки или два Control-Ds в середине строки.

Для Unix это применяется только при чтении с терминала; если вы читаете из файла, control-D - это еще один непечатаемый символ, и он не вызывает условие конца файла. Windows, похоже, распознает control-Z как триггер конца файла даже при чтении из файла диска.

Итог: разные операционные системы ведут себя по-разному, в основном по неясным историческим причинам. С++ предназначен для работы с любым из этих поведений, поэтому он не является специфическим для некоторых деталей.

Ответ 3

Это вызвано cin → ^ Z будет оцениваться как false.

Подробнее: cin.eof() вернет true, так что while, которое неявно вызывает eof(), вернет false и, следовательно, завершите цикл.

Если вы введете 12 ^ Z, eof() вернет false, поскольку он может анализировать допустимое входное значение, поэтому он не остановит цикл.

Вам может быть интересно это также:

SO по семантике флагов