Каков лучший способ проверить EOF и ошибку fgetc ()? [дубликат]

этот вопрос уже есть ответ здесь:

Я всегда использую этот подход

int c;
while ((c = fgetc(fp))!=EOF)
{
    printf("%c", c);
}

как мне кажется, более четкий и надежный. Но на мой ответ ... --16-->ссылке, chux прокомментировал это

Если (feof(fp)) более робастно чем int c; while ((c = fgetc (fp))!=EOF)

As

    while(1)
    {
        c = fgetc(fp);
        if ( feof(fp) )
        {
            break ;
        }
        printf("%c", c);
    }

является более надежным, чем первая версия. Так какую версию мне использовать? Пожалуйста, объясните мне, почему эта версия лучше.

редактировать

на вопрос почему " while ( !feof (файл) )" всегда неправ? там спросили, почему feof () в контуре управления всегда ошибается. Но проверка feof() В если условие в правильном пути всегда неправильно? Объяснения очевидны.

3 ответов


Я обычно программирую входные циклы следующим образом:

int c;

while ((c = fgetc(fp)) != EOF) {
    /* do something with c here */
}

/* check if EOF came from an end-of-file or an error */
if (ferror(fp)) {
    /* error handling here */
}

вы обычно не должны использовать условие цикла, как это:

while (!feof(fp)) {
    /* do stuff */
}

или

for (;;) {
    c = fgetc(fp);
    if (feof(fp))
        break;
}

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

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


проблема тестирования для условия ошибки возникла из-за случай в с.

fgetc() возвращает int. Его значения находятся в диапазоне unsigned char и EOF (некоторые отрицательное число).

int ch;
while ((ch = fgetc(fp)) != EOF) {
  // do something with ch
}
if (ferror(fp)) Handle_InputError();
if (feof(fp)) Handle_EndOffFile();  // Usually nothing special

но C позволяет unsigned char иметь более широкий диапазон, чем положительное число int. Преобразованиеunsigned char до int имеет определенное поведение реализации, которое может привести к unsigned char значение преобразуется в отрицательное int - и тот, который соответствует EOF.

такие платформы встречаются редко и не в основном потоке 2015 года. Большинство будет иметь UCHAR_MAX <= INT_MAX и выше стиль обычно используется. Сомнительно, что эти платформы когда-либо станут общими из-за количества кода, как указано выше, который полагается на EOF отличается от unsigned charпреобразовано в int.

если код должен обрабатывать редкий случай, когда UCHAR_MAX > INT_MAX, потом

int c;
for (;;)
{
    c = fgetc(file);
    if (c == EOF) {
      if (feof(file)) break;
      if (ferror(file)) break;
      // fall through if both if's fail.
    }
    // do stuff with c
}

популярная ссылка в while (!feof (файл) ) всегда неправ? выделяет код ошибки часто делает в использовании результатов fgetc(in) перед проверкой на наличие проблем. Оба кода выше проверяют условия ошибки перед использованием результата fgetc().


2-й код обрабатывает все ситуации, включая те, которые могут применяться только к компьютеру, сидящему в какой-то давно забытой куче мусора. Первый гораздо более распространен.


предложенное улучшение не лучше, даже менее надежно.

как пояснил здесь, он входит в бесконечный цикл, если происходит ошибка чтения (без eof). В таком случае ...--0--> вернутся 0 while fgetc возвращает EOF.

ваша версия не имеет этой проблемы.

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