Путаница с == EOF vs feof

Я открыл файл, поток найден по адресу указателя ptr. Я пытаюсь выяснить, пустой ли файл. Используя следующие

if (fgetc(ptr) != EOF)

работает как ожидалось. Когда файл пуст, оператор не выполняется. Когда файл не пуст, оператор не выполняется.

Однако, используя

if (!feof(ptr))

всегда выполняет оператор.

Почему это происходит? Есть ли способ использовать функцию feof?

Ответ 1

Есть ли способ использовать функцию feof?

Да, есть. После того, как функция ввода вернула значение, которое указывает, что у него больше нет ввода для обработки, вы можете вызвать feof() и/или ferror(), чтобы определить, было ли условие вызвано достижением конца ввода или некоторым условием ошибки.

Это единственное допустимое использование для функций feof() и ferror().

Результат, который указывает, что больше не осталось ввода, отличается от одной функции к другой. Например, fgets() возвращает значение EOF, а fread() возвращает некоторое значение, меньшее количества запрошенных записей. Вам нужно прочитать документацию для каждой функции ввода, чтобы увидеть, как она работает.

Ответ 2

В стандартной библиотеке C "конец файла" не является независимым условием самоопределения. "Конец файла" - это просто состояние файла, установленное предыдущей операцией чтения. Пока вы не выполните операцию чтения и пока эта операция чтения не столкнется с фактическим концом файла, состояние "eof" не установлено, а feof() возвращает 0.

Многие (большинство) стандартных функций ввода-вывода в стандартной библиотеке C уже возвращают некоторый код завершения, который можно использовать для определения состояния "конца файла" (например, fgetc() return EOF value). Это означает, что большую часть времени вызов feof() не требуется.

Другими словами, если вы думаете о "конце файла" как кирпичной стене, в стандартной библиотеке C недостаточно просто стоять прямо перед этой стеной, чтобы обнаружить ее. Для того, чтобы обнаружить его присутствие, необходимо наткнуться на эту стену со лба.

Когда вы открываете пустой файл, вы начинаете в состоянии "прямо перед стеной". На данный момент условие "конец файла" еще не обнаружено. Вы должны попробовать что-то прочитать, чтобы врезаться в эту стену и тем самым обнаружить ее присутствие.

Причины этого дизайна совершенно логичны. Язык C предназначен для поддержки различных входных потоков и файловых систем, включая 1) файловые системы, которые вообще не хранят размеры файлов, а также 2) файловые системы, которые знают только приблизительный размер файла (например, округленный до ближайшего кластера). В таких файловых системах конец файла обычно обозначается специальным маркером. Вы не знаете, где находится этот маркер, пока вы не столкнетесь с ним при чтении файла. (По той же причине потоки C не гарантируют поддержку позиционирования из SEEK_END origin в функции fseek.)

Как отметил в комментариях @Barmar, еще лучший пример входного потока без предопределенной позиции "конец файла" - это стандартный ввод, связанный с терминалом.

Ответ 3

feof(f) всегда будет возвращать false сразу после открытия файла, потому что если вы даете значение флага, который инициализируется значением false и устанавливается в true только после того, как по крайней мере одна операция чтения завершится с ошибкой.

Ответ 4

Вы можете использовать feof следующим образом:

fgetc(fp);
if (feof(fp))
  ...

feof проверяет индикатор конца файла, установленный после чтения, которое пыталось прочитать на или после конца файла. Это полезно в ситуациях, когда код, который вы не контролируете, читает из файла, и вы хотите остановить обработку после того, как файл был исчерпан.