Представлять EOF в коде C?

Символ новой строки представлен "\n" в коде C. Есть ли эквивалент для символа конца файла (EOF)?


person static_rtti    schedule 12.09.2012    source источник
comment
В вопросе ошибочно предполагается, что EOF является символом, хотя на самом деле это условие. На самом деле, если бы это был был символ, это уже не был бы конец, не так ли?   -  person Kerrek SB    schedule 12.09.2012
comment
Нет символа EOF. EOF – это значение выходя за пределы, используемое для обозначения состояния EOF. Он не равен никакому символьному значению (как читается getc() и др.)   -  person wildplasser    schedule 12.09.2012
comment
@Kerrek SB: вы правы, но обратите внимание, что некоторые операционные системы в прошлом действительно имели символ EOF, который был встроен в файл, например. CP/M использовала для этого Control-Z.   -  person Paul R    schedule 12.09.2012


Ответы (11)


EOF не является символом (в большинстве современных операционных систем). Это просто условие, которое применяется к файловому потоку при достижении конца потока. Путаница возникает из-за того, что пользователь может сигнализировать EOF для ввода в консоль, введя специальный символ (например, Control-D в Unix, Linux, и др.), но этот символ не видно работающей программе, оно перехватывается операционной системой, которая, в свою очередь, сигнализирует процессу EOF.

Примечание: в некоторых очень старых операционных системах EOF был символом, например. Control-Z в CP/M, но это был грубый хак, чтобы избежать накладных расходов на сохранение фактической длины файлов в каталогах файловой системы.

person Paul R    schedule 12.09.2012
comment
@EricPostpischil: стандарт C (косвенно) гарантирует, что возвращаемое значение из getchar() et al является либо допустимым символом, либо отдельным кодом, EOF, который не является кодом допустимого символа. EOF, которое расширяется до целочисленного константного выражения с типом int и отрицательным значением, которое возвращается несколькими функциями для указания конца файла, то есть больше никаких входных данных из потока;' и 'функция fgetc получает [следующий] символ как unsigned char, преобразованный в int". Таким образом, в любой системе, где sizeof(char) != sizeof(int), EOF отличается от любого char. - person Jonathan Leffler; 12.09.2012
comment
Текст, который вы цитируете, не указывает, что EOF должен отличаться от любого символьного значения. Обычно EOF не равен никакому символьному значению, но это не гарантируется стандартом C. - person Eric Postpischil; 12.09.2012
comment
Также обратите внимание, что даже сегодня в Windows Ctrl-Z в файле вызовет условие EOF, если он открыт в текстовом режиме. Microsoft очень серьезно относится к своей обратной совместимости с CP/M. - person Michael Burr; 13.09.2012
comment
@Michael Burr: черт возьми, я этого не знал - так что в некотором смысле мы действительно не так уж далеко ушли от эпохи CP / M. - person Paul R; 13.09.2012
comment
@MichaelBurr: Вы уверены, что это Windows, а не специфичная для компилятора реализация stdio? Насколько я знаю, в Windows даже нет условия открытия в текстовом режиме. - person Ben Voigt; 02.08.2014
comment
@BenVoigt - Управляющий символ EOF (ASCII-символ 0x1a) по-прежнему обрабатывается и заканчивается файлом встроенными утилитами командной строки Windows. Например, команда copy при использовании с параметром /a (режим ASCII) добавит код символа EOF в конец добавляемых файлов. Точно так же команда type подчиняется символам EOF, которые встречаются в текстовых файлах. Является пережитком MS-DOS. ‹/Урок истории› - person vercellop; 22.05.2018
comment
@vercellop: Да, интерпретатор команд имеет большую обратную совместимость с DOS. Но хотя он связан с Windows, это всего лишь инструмент пользовательского режима, а не часть ОС. - person Ben Voigt; 22.05.2018

EOF не является персонажем. Этого не может быть: (двоичный) файл может содержать любой символ. Предположим, у вас есть файл с постоянно увеличивающимися байтами, начиная с 0 1 2 3 ... 255 и еще раз 0 1 ... 255, всего 512 байт. Какой бы из этих 256 возможных байтов вы ни выбрали EOF, файл будет обрезан.

Вот почему getchar() и др. вернуть int. Диапазон возможных возвращаемых значений — это значения, которые может иметь char, плюс подлинное значение int EOF (определенное в stdio.h). По этой же причине преобразование возвращаемого значения в char до проверки EOF не сработает.

Обратите внимание, что некоторые протоколы имеют "символы" EOF. В ASCII есть «Конец текста», «Конец передачи», «Конец блока передачи» и «Конец среды». В других ответах упоминались старые ОС. Я сам ввожу ^D в Linux и ^Z в консолях Windows, чтобы перестать вводить программы. (Но файлы, прочитанные через конвейеры, могут иметь символы ^D и ^Z в любом месте и сообщать об окончании EOF только тогда, когда в них заканчиваются байты.) Строки C заканчиваются символом '\0', но это также означает, что они не могут содержать персонаж '\0'. Вот почему все функции нестроковых данных C работают с использованием массива char (чтобы содержать данные) и size_t (чтобы знать, где заканчиваются данные).

Изменить: стандарт C99 §7.19.1.3 гласит:

Макросы [...]
EOF
, которые расширяются до целочисленного константного выражения с типом int и отрицательным значением, которое возвращается несколькими функциями для указания конца -of-file, то есть больше никаких входных данных из потока;

person aib    schedule 12.09.2012
comment
Ваше редактирование не показывает, что EOF не равен значению символа. Тот факт, что EOF указывает на конец файла, не исключает того, что он равен значению char. Тот факт, что EOF является отрицательным, не мешает ему равняться значению char. (Разрешение EOF быть символьным значением является неприятностью, но, поскольку ответ, который я связал с состояниями, не мешает реализации C соответствовать стандарту C.) - person Eric Postpischil; 12.09.2012
comment
Это не меняет проблемы. Люди, выполняющие ((charVar = getchar()) == EOF), увидят некорректное поведение. Вы говорите, что они могут получить преждевременный, ложный EOF, когда они прочитают это значение char, которое оказывается равным EOF при повышении до int, вместо того, чтобы зацикливаться навсегда, потому что никакое char никогда не будет равно EOF. Решение все то же: ((intVar = getchar()) == EOF) - person aib; 13.09.2012
comment
Вы должны были сказать, что стандарт C не гарантирует, что EOF не равно значению char. В самом деле, даже если в реализации используется один и тот же тип char и int, они по-прежнему являются разными типами для стандарта и тех, которые ему соответствуют. - person aib; 13.09.2012
comment
@EricPostpischil Значит, все эти 3 наиболее популярных ответа в корне неверны? Все трое начинают говорить, что варианты EOF — это не персонаж. Вы знаете другой источник с правильным ответом? - person Santropedro; 20.07.2019
comment
@Santropedro: Да, ответы неверны. Различные подпрограммы стандартной библиотеки возвращают символ как unsigned char, преобразованный в int, поэтому он должен иметь неотрицательное значение, которое не может равняться EOF, поскольку EOF отрицательно. Однако одно из определений «символа» в стандарте C — это «битовое представление, умещающееся в байте». И многие люди обрабатывают символы, используя тип char, который может быть подписан. (На самом деле, fgets принимает char *.) Тогда возможно иметь char x, значение которого равно EOF, но которое можно корректно распечатать с помощью fputc и других функций. - person Eric Postpischil; 20.07.2019
comment
@Santropedro: Чтобы правильно ответить на вопрос, это означает, что нужно обнаружить EOF, используя возвращаемое значение из таких функций, как fgetc, которая возвращает символ как unsigned char, преобразованный в int, или EOF. Это будет работать во всех, кроме экзотических гипотетических реализациях C, обсуждаемых в ссылке, которую я предоставил. (Чтобы написать код даже для этих реализаций, используйте функцию feof.) Но не следует предполагать, что значение char не равно EOF. - person Eric Postpischil; 20.07.2019

Нет. EOF — это не символ, а состояние дескриптора файла.

Хотя в кодировке ASCII есть управляющие символы, обозначающие конец данных, в целом они не используются для обозначения конца файлов. Например, EOT (^D), что в некоторых случаях почти означает то же самое.

Когда стандартная библиотека C использует целое число со знаком для возврата символов и использует -1 для конца файла, это на самом деле просто сигнал, указывающий, что произошла ошибка. У меня нет доступного стандарта C, но процитирую SUSv3:

Если индикатор конца файла для потока установлен или если поток находится в конце файла, должен быть установлен индикатор конца файла для потока, а функция fgetc() должна возвращать EOF. Если возникает ошибка чтения, должен быть установлен индикатор ошибки для потока, функция fgetc() должна возвращать EOF и должна устанавливать errno, чтобы указать на ошибку.

person pmakholm    schedule 12.09.2012

Я прочитал все комментарии. Интересно заметить, что происходит, когда вы распечатываете это:

printf("\nInteger =    %d\n", EOF);             //OUTPUT = -1
printf("Decimal =    %d\n", EOF);               //OUTPUT = -1
printf("Octal =  %o\n", EOF);                   //OUTPUT = 37777777777
printf("Hexadecimal =  %x\n", EOF);             //OUTPUT = ffffffff
printf("Double and float =  %f\n", EOF);        //OUTPUT = 0.000000
printf("Long double =  %Lf\n", EOF);            //OUTPUT = 0.000000
printf("Character =  %c\n", EOF);               //OUTPUT = nothing

Как мы видим здесь, EOF НЕ является символом (чем бы то ни было).

person carloswm85    schedule 16.02.2018
comment
Вы получаете UB, потому что используете неправильный спецификатор формата. EOF не является числом с плавающей запятой, двойным или длинным двойным числом, поэтому очевидно, что печать его как типа с плавающей запятой не работает. - person phuclv; 22.08.2020
comment
@phuclv Можете ли вы сказать мне, что такое UB? - person carloswm85; 29.09.2020

Это зависит от системы, но часто -1. См. здесь

person onoma    schedule 12.09.2012

Я думаю, что это может варьироваться от системы к системе, но один из способов проверки - просто использовать printf

#include <stdio.h>
int main(void)
{
    printf("%d", EOF);
    return 0;
}

Я сделал это в Windows, и -1 было напечатано на консоли. Надеюсь это поможет.

person Keith Miller    schedule 12.09.2012
comment
Если eof является символом, почему вы печатаете с помощью %d? - person Koray Tugay; 06.06.2015

Значение EOF нельзя спутать ни с каким реальным символом.

Если a= getchar(), то мы должны объявить a достаточно большим, чтобы вместить любое значение, которое возвращает getchar(). Мы не можем использовать char, так как a должно быть достаточно большим, чтобы содержать EOF в дополнение к символам.

person Harsh Vardhan    schedule 27.03.2016
comment
Этот ответ неоднозначен. В то время как первая часть верна, вторую часть, описывающую размер a, трудно понять. Я отредактировал ваш пост, чтобы внести немного ясности. - person Luke Taylor; 27.03.2016

Ответ НЕТ, но...

Вы можете запутаться из-за поведения fgets()

Из http://www.cplusplus.com/reference/cstdio/fgets/ :

Считывает символы из потока и сохраняет их как строку C в str до тех пор, пока не будет прочитано (num-1) символов или не будет достигнут либо перевод строки, либо конец файла, в зависимости от того, что произойдет раньше.

person betontalpfa    schedule 23.02.2017

Символ EOF, распознаваемый интерпретатором команд в Windows (и MSDOS, и CP/M), равен 0x1a (десятичное число 26, также известное как Ctrl+Z или SUB).

Его все еще можно использовать сегодня, например, для обозначения конца удобочитаемого заголовка в двоичном файле: если файл начинается с "Some description\x1a", пользователь может вывести содержимое файла на консоль с помощью команды TYPE, и дамп остановится на EOF персонаж, т.е. напечатать некоторое описание и остановиться, вместо того, чтобы продолжать с последующим мусором.

person Axel Rietschin    schedule 01.09.2014

Есть константа EOF типа int, найденная в stdio.h. Ни в одном стандарте не существует эквивалентного символьного литерала.

person Lundin    schedule 12.09.2012

Я много исследовал сигнал EOF. В книге Денниса Ритчи «Программирование на C» он впервые встречается при вводе команд putchar() и getchar(). Это в основном отмечает конец ввода строки символов.

Например. Давайте напишем программу, которая ищет два числовых входа и печатает их сумму. Вы заметите, что после каждого числового ввода вы нажимаете Enter, чтобы отметить сигнал о завершении действия ввода. Но при работе со строками символов Enter читается как просто еще один символ ['\n': символ новой строки]. Чтобы отметить прекращение ввода, введите ^Z (Ctrl + Z на клавиатуре) в совершенно новой строке, а затем введите. Это сигнализирует о выполнении следующих строк команды.

#include <stdio.h>

int main()
{
char c;
int i = 0;
printf("INPUT:\t");
c = getchar();

while (c != EOF)
{
   ++i;
   c = getchar();
   
};

printf("NUMBER OF CHARACTERS %d.", i);

return 0;}

Выше приведен код для подсчета количества символов, включая символы '\n' (новая строка) и '\t' (пробел). Если вы не хотите считать символы новой строки, сделайте следующее:

#include <stdio.h>

int main()
{
char c;
int i = 0;
printf("INPUT:\t");
c = getchar();

while (c != EOF)
{
    if (c != '\n')
    {
        ++i;
    }

    c = getchar();
    };

printf("NUMBER OF CHARACTERS %d.", i);

return 0;}. 

СЕЙЧАС ГЛАВНОЕ ДУМАЕМ, КАК ДАТЬ ВВОД. ЭТО ПРОСТО: напишите всю историю, которую хотите, затем перейдите на новую строку и введите ^Z, а затем введите еще раз.

person Samarthya Singh    schedule 18.12.2020