vitiral
vitiral

Reputation: 9248

Unix get specific error of fread, fgetc, etc?

I would like to get the specific error (EAGAIN) after reading this pipe. How do I do so?

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int main() {
  int rw[2]; assert(!pipe(rw));
  int r = rw[0], w = rw[1];
  fcntl(r, F_SETFL, O_NONBLOCK);
  printf("This will return EAGAIN\n");
  printf(" read -> %i\n", read(r, buf, 10));
  printf(" errno = %i \"%s\" (EAGAIN=%i)\n", errno, strerror(errno), EAGAIN);

  errno = 0;
  FILE* f = fdopen(r, "r");
  printf(" fgetc -> %i (EOF=%i) errno=%i\n", fgetc(f), EOF, errno);
  printf(" ferror -> %i\n", ferror(f));
}

Prints

This will return EAGAIN
 read -> -1
 errno = 11 "Resource temporarily unavailable" (EAGAIN=11)
This doesn't give me any info
 fgetc -> -1 (EOF=-1) errno=0
 ferror -> 1

Upvotes: 0

Views: 44

Answers (1)

vitiral
vitiral

Reputation: 9248

It was programmer error, thanks @Shawn for helping in the comments.

The order of evaluation of function arguments isn't specified by C. Even if errno is left in a useful state after fgetc() errors, printf() might be getting passed its value before fgetc() is called if the arguments are evaluated right to left.

I now realize that fread() and friends don't mention errno at all -- meaning (I guess?) that they also don't modify errno if an error occurs. Pretty interesting!

I've modified the second bit with

  printf("Errno has the answers!\n");
  FILE* f = fdopen(r, "r");
  errno = 0;
  printf(" errno has been set to %i\n", errno);
  printf(" fgetc -> %i (EOF=%i)\n", fgetc(f), EOF);
  printf(" errno=%i (pre ferror)\n", errno);
  printf(" ferror -> %i\n", ferror(f));
  printf(" errno=%i\n", errno);

Which prints

Errno has the answers!
 errno has been set to 0
 fgetc -> -1 (EOF=-1)
 errno=11 (pre ferror)
 ferror -> 1
 errno=11

Upvotes: 0

Related Questions