Как feof () работает в C

Проверяет ли feof () на eof текущую позицию filepointer или проверяет позицию рядом с текущим файловым указателем?

Спасибо за вашу помощь !

В каждом streamе FILE есть внутренний флаг, который указывает, пытался ли вызывающий объект прочесть предыдущий конец файла. feof возвращает этот флаг. Флаг не указывает, находится ли текущая позиция файла в конце файла, только если предыдущее чтение попыталось прочитать за конец файла.

В качестве примера давайте рассмотрим, что происходит, при чтении файла, содержащего два байта.

 f = fopen(filename, "r"); // file is opened assert(!feof(f)); // eof flag is not set c1 = getc(f); // read first byte, one byte remaining assert(!feof(f)); // eof flag is not set c2 = getc(f); // read second byte, no bytes remaining assert(!feof(f)); // eof flag is not set c3 = getc(f); // try to read past end of the file assert(feof(f)); // now, eof flag is set 

Вот почему неправильный способ использования eof при чтении файла:

 f = fopen(filename, "r"); while (!feof(f)) { c = getc(f); putchar(c); } 

Из-за того, как работает feof , флаг конца файла устанавливается только после того, как getc пытается прочитать за конец файла. getc затем вернет EOF , который не является символом, а конструкция цикла заставляет putchar пытаться записать его, что приводит к ошибке или выходу мусора.

Каждый метод ввода стандартной библиотеки C возвращает признак успеха или сбоя: getc возвращает специальное значение EOF если оно пыталось прочитать за конец файла, или если при чтении произошла ошибка. Особым значением является то же самое для конца файла и ошибки, и в этом заключается правильный способ использования feof : вы можете использовать его для различения между файлами и ошибками.

 f = fopen(filename, "r"); c = getc(f); if (c == EOF) { if (feof(f)) printf("it was end-of-file\n"); else printf("it was error\n"); } 

Существует еще один внутренний флаг для объектов FILE для ситуаций с ошибками: ferror . Часто бывает проще проверить ошибки вместо «не конец файла». Идиоматический способ чтения файла в C выглядит так:

 f = fopen(filename, "r"); while ((c = getc(f)) != EOF) { putchar(c); } if (ferror(f)) { perror(filename): exit(EXIT_FAILURE); } fclose(f); 

(Некоторая проверка ошибок была исключена из примеров здесь, для краткости.)

Функция feof довольно редко используется.

Вы можете лучше понять, как работает feof , зная, как это реализовано. Вот упрощенная версия о том, как библиотека 7-го издания Unix stdio реализует feof . Современные библиотеки очень похожи, добавление кода, обеспечивающего безопасность streamов, повышение эффективности и более чистую реализацию.

 extern struct _iobuf { char *_ptr; int _cnt; char *_base; char _flag; char _file; } _iob[_NFILE]; #define _IOEOF 020 #define feof(p) (((p)->_flag&_IOEOF)!=0) #define getc(p) (--(p)->_cnt>=0? *(p)->_ptr++&0377:_filbuf(p)) int _filbuf(FILE *iop) { iop->_ptr = iop->_base; iop->_cnt = read(fileno(iop), iop->_ptr, BUFSIZ); if (iop->_cnt == 0) { iop->_flag |= _IOEOF; return(EOF); } return(*iop->_ptr++ & 0377); 

}

Библиотека stdio поддерживает с каждым файлом структуру, содержащую внутренний буфер, на который указывает _base . Текущий символ в буфере указывается _ptr а количество доступных символов содержится в _cnt . Макрос getc , который является базой для множества функций более высокого уровня, таких как scanf , пытается вернуть символ из буфера. Если буфер пуст, он будет называть _filbuf для его заполнения. _filbuf в свою очередь, вызовет read . Если read возвращает 0, это означает, что больше данных не доступно, _filbuf установит флаг _IOEOF , который проверяет каждый раз, когда вы вызываете его, чтобы вернуть true.

Как вы можете понять из вышеизложенного, feof вернет true при первом попытке прочитать символ за концом файла (или функция библиотеки пытается от вашего имени). Это имеет тонкие последствия для поведения различных функций. Рассмотрим файл, содержащий один символ: цифру 1 . После того, как вы прочитаете этот символ с помощью getc , feof вернет false, потому что флаг _IOEOF не установлен; никто еще не пробовал прочитать за конец файла. Вызов getc снова приведет к вызову для read , настройке флага _IOEOF , и это приведет к возврату true. Однако после чтения номера из того же файла с помощью fscanf("%d", &n) feof немедленно вернет true, потому что fscanf попытается прочитать дополнительные цифры целого числа.