Reputation: 9248
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
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