7

I'm trying to check when fread() raises an error, so I use ferror().

chunk = fread(buf, 1, 100, file);
if (ferror(file))
  {
    return errno;
  }

But, ferror() man page (man 3 ferror, or just man ferror) says:

ERRORS
These functions should not fail and do not set the external variable errno.

So, how can I know the error type occurred when file has been read, although fread() and ferror() didn't set errno?

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
Mahmoud Mubarak
  • 139
  • 1
  • 11
  • 3
    Did you read [fread(3)](http://man7.org/linux/man-pages/man3/fread.3.html) ? It has a documented behavior on error ! – Basile Starynkevitch Oct 24 '16 at 09:05
  • 2
    yes, it doesn't mention anything about setting errno. – Mahmoud Mubarak Oct 24 '16 at 09:06
  • 5
    @BasileStarynkevitch I think his point was exactly that. Sure `ferror` can tell you an error happened, but since `fread` is *not* documented to set `errno`, how can he tell *what the actual error was*, if he can at all, since `errno` won't reflect the specific error condition that lit up the stream error state? – WhozCraig Oct 24 '16 at 09:09
  • 1
    Related: [Does stdio always set errno?](http://stackoverflow.com/questions/10672095/does-stdio-always-set-errno). – Martin R Oct 24 '16 at 09:11

2 Answers2

10

You can't get there from here.

fread does not set errno (as you have discovered), and as such you cannot really determine much about a specific error state; only that there is one. The exact nature of the error is generally implementation-dependent. There is no C standard-library-based portable way to gather it .

For specific system-level errors, you can slum it to system-calls, possibly suffering with the pitfalls like poor/nonexistent IO buffering along the way. There POSIX can somewhat come to your rescue. Calls like read, do set errno and have a fairly detailed set of possible outcomes. That may be an option for you if the platform you're working with is POSIX compliant and the code is really so critical to be in-the-know.

But from the C standard library, you're not going to find much beyond being told an error has happened. Generally you'll find you don't need more than that anyway.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • 2
    POSIX requires `fread` to set `errno` on an error. From the POSIX documentation on `fread`, "Otherwise, if a read error occurs, the error indicator for the stream shall be set, and `errno` shall be set to indicate the error. " – David Hammen Feb 26 '19 at 13:32
  • @DavidHammen: that snippet is marked as a POSIX _extension_ [CX]. Still, I wonder why GNU does not follow this extension. Isn't it supposed to when `_XOPEN_SOURCE` / `_POSIX_SOURCE` are defined with appropriate values? – MestreLion Sep 01 '20 at 02:56
4

Those functions don't use errno, so you shouldn't either.

It is worth noting that you can tell if everything went smoothly from the return value of fread(). If the return value of fread() differs from the passed nmemb parameter (100 in your case), then you either reached the end of your file or an error occured reading it (source). So test only in that case:

Just drop the use of errno alltogether:

chunk = fread(buf, 1, 100, file);
if (chunk != 100) { // If fread() returns a number different to the nmemb parameter, either error or EOF occured
    if (ferror(file))
      {
        printf("Error occured while reading file.");
        return -1; // Or what ever return value you use to indicate an error
      }
}
Magisch
  • 7,312
  • 9
  • 36
  • 52
  • @BasileStarynkevitch `fread` has documented behavior on error or end of file. You need to use `ferror()` to check if it was an error or `feof()` for end-of-file. – Magisch Oct 24 '16 at 09:09