Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is clearerr used for?

Tags:

c

I'm trying to understand when the stdio function clearerr() should be used.

For example, if I fread() or fwrite() on a valid FILE* and get a short count and ferror is true, what can I do?

From what I've read so far, fread() and fwrite() are robust and will block and/or retry (if there are locks and/or interrupts which could happen in lower level functions) so there never seems any point in using clearerr() because fread or fwrite errors will be so catastrophic there is no point in trying to recover.

Additionally, ferror() only tells me that there is an error, not what the error is.

   #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 );
   }
like image 886
Kelvin Avatar asked Jun 25 '19 13:06

Kelvin


4 Answers

There is at least one real world use case for clearerr: when you want to mimic tail -f on a file that is not opened in exclusive mode. That means that another (or many other) process(es) write at the end of a file, and one process repeatedly reads even after having reached the end of file in order to look whether new data has arrived. In that case, could would look like:

for (;;) {
    if (NULL == fgets(line, sizeof(line), fd)) {
        sleep(n);
        clearerr(fd);     // reset EOF condition
    }
    else {
        fputs(line, fdout);
    }
}
like image 181
Serge Ballesta Avatar answered Nov 05 '22 01:11

Serge Ballesta


Functions that set the error status of a FILE (as reported by ferror) do not clear it even if later called successfully. Likewise if you encounter the end of file while reading, it will not be cleared automatically even if the file later has more data available.

Basically this means that if you are using ferror to check for an error state and you have some way of recovering from it, the ferror will keep indicating an error until you use clearerr.

In your example, if you just use the return value of fread as the condition for terminating the read (i.e., EOF and any type of error are considered final), there is no need to clearerr: just fall through to fclose (and perhaps use ferror to determine whether to print an error message).

On the other hand, if the FILE is in fact a stream on which read can later succeed, and you detect (or assume) that specific condition and retry, you should clearerr before retrying or you will keep seeing the old error condition on future attempts.

Likewise, as pointed out in comments, clearerr also clears the end of file state, so this also applies when using feof to check for the end of file. (Note, however, that you generally shouldn't use !feof(file) as the loop condition when reading.)

like image 24
Arkku Avatar answered Nov 05 '22 01:11

Arkku


clearerr() clears the error and EOF flags from a stream.

Say FILE were like this:

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

This would set file->error and file->eof to 0.

Some reasons for doing this include file I/O, such as when a file gives EOF, but then another program (or another thread, etc.) appends to it. If you clear the error after doing this, you can have your program act as sort of a tail -f-substitute.

like image 2
S.S. Anne Avatar answered Nov 05 '22 01:11

S.S. Anne


clearerr() clears both the error and end-of-file flags.

A pedantic use of 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.
  ...?
}

Use 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;
}
like image 1
chux - Reinstate Monica Avatar answered Nov 05 '22 02:11

chux - Reinstate Monica