Для чего используется clearerr? - PullRequest
7 голосов
/ 25 июня 2019

Я пытаюсь понять, когда следует использовать функцию stdio clearerr().

Например, если я fread() или fwrite() на действительном FILE* и получу короткий счет, а ferror верно, что я могу сделать?

Из того, что я читал до сих пор, fread() и fwrite() являются надежными и будут блокировать и / или повторять попытки (если есть блокировки и / или прерывания, которые могут произойти в функциях более низкого уровня), поэтому никогда не возникает никаких Смысл clearerr() в том, что ошибки fread или fwrite будут настолько катастрофическими, что нет смысла пытаться их восстановить.

Кроме того, ferror() только говорит мне, что есть ошибка, а не то, что это ошибка.

   #define SZ 1024
   FILE* fp = fopen( "foo", "r" );
   if ( fp ) {
      char b[SZ];
      int ch_count = fread( b, sizeof(char), SZ, fp );
      if ( ch_count != SZ && ferror( fp ) ) {
          // how would clearerr() be used. I don't know? 
          // ....
          // should I drop through here to fclose? (when I've got an ferror)
      }
      fclose( fp );
   }

Ответы [ 4 ]

8 голосов
/ 25 июня 2019

Для clearerr существует как минимум один реальный случай использования: когда вы хотите имитировать tail -f для файла, который не открывается в монопольном режиме. Это означает, что другой (или многие другие) процесс (ы) записывают в конец файла, и один процесс многократно читает даже после достижения конца файла , чтобы посмотреть, поступили ли новые данные. В таком случае, может выглядеть так:

for (;;) {
    if (NULL == fgets(line, sizeof(line), fd)) {
        sleep(n);
        clearerr(fd);     // reset EOF condition
    }
    else {
        fputs(line, fdout);
    }
}
3 голосов
/ 25 июня 2019

Функции, которые устанавливают состояние ошибки FILE (как сообщается ferror), не очищают его, даже если впоследствии он успешно вызывается. Аналогично, если во время чтения вы столкнетесь с концом файла, он не будет очищен автоматически, даже если в файле позже будет доступно больше данных.

В основном это означает, что , если вы используете ferror для проверки состояния ошибки и у вас есть какой-то способ восстановления после него, ferror будет продолжать отображать ошибку до тех пор, пока вы не используете clearerr.

В вашем примере, если вы просто используете возвращаемое значение fread в качестве условия для прекращения чтения (т. Е. EOF и любой тип ошибки считаются окончательными), нет необходимости clearerr: просто упасть до fclose (и, возможно, используйте ferror, чтобы определить, печатать ли сообщение об ошибке).

С другой стороны, если FILE на самом деле является потоком, для которого позднее чтение может быть успешно выполнено, и вы обнаруживаете (или предполагаете) это конкретное условие и повторите попытку, вы должны clearerr перед повторной попыткой, или вы будете продолжать видеть старое состояние ошибки при последующих попытках.

Аналогично, как указано в комментариях, clearerr также очищает состояние конца файла, поэтому это также применяется при использовании feof для проверки конца файла. (Однако обратите внимание, что обычно не следует использовать !feof(file) в качестве условия цикла при чтении.)

2 голосов
/ 25 июня 2019

clearerr() очищает ошибку и флаги EOF из потока.

Скажем FILE было так:

typedef struct {
    int fd;
    char *buf;
    int error;
    int eof;
} FILE;
FILE *file;

Это установит file->error и file->eof в0.

Некоторые причины для этого включают файловый ввод-вывод, например, когда файл дает EOF, но затем к нему добавляется другая программа (или другой поток и т. Д.).Если после этого вы устраните ошибку, ваша программа может выступать в роли tail -f -замены.

1 голос
/ 26 июня 2019

clearerr() очищает флаги как ошибок, так и конца файла.

Педантичное использование clearerr():

// Return -1 on end-of-file
// Return -2 on rare file error
// Else return the unsigned char value
int my_get_quandry() {
  // At this point, the file end-of-file flag may be set.
  // At this point, the file file error flag may be set.
  // They may both be set.

  // Attempt to read another
  int ch = fgetc();
  if (ch != EOF) {
    return ch;
  }
  // Now was the EOF due to a end-of file or error?
  // feof() is true if end-of-file just occurred OR if end-of-file was set earlier
  // ferror() is true if error just occurred OR if error was set earlier
  // If only one feof() or ferror() is true, we know  why EOF just occurred,
  // Yet if both set, we do not know.
  ...?
}

Использование clearerr()

// Return -1 on end-of-file
// Return -2 on rare file error
// Else return the unsigned char value
int my_get_crystal() {
  clearerr(stdin);

  // Attempt to read another
  int ch = fgetc();
  if (ch != EOF) {
    return ch;
  }
  // Now EOF due to at most one reason
  if (feof(stdin)) return -1;
  if (ferror(stdin)) return -2;

  // if code reaches this point, it is due to the odd-ball platform of `char` having the
  // same range as `int`.  But let us leave that platform for another day.
  return ch;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...