Search code examples
c++clibc

C++ and syscalls: ignoring return value and checking errno instead


Error checking in C is a task that is very verbose and makes the code unreadable. In C++ you have exceptions, but when I use C++ to call C functions, the headaches come back. I wish there was a "syscalls wrapper for C++" where all the functions have the same names and parameters, but where errors are turned into exceptions and that's all. That would be game changing.

Trying to solve that verbosity problem when interacting with C functions/syscalls from C++, I came up with the following solution (simplified here):

void ko(char const* doingwhat) // or ko_check or whatever
{
   if (errno != 0)
      throw std::runtime_error(doingwhat);
}

void some_method()
{
    errno = 0;
    int fd = open(blablabla, blablabla); ko("opening the file");
    void* ptr = mmap(blablabla, blablabla); ko("mmaping it");
    
    struct stat st; fstat(fd, &st); ko("getting stats");
    // etc etc etc
}

The method is to directly ignore return values and check errno instead. Since errno is thread local and can only change if there's an error in a libc call, with setting errno = 0 at the beginning of your method would be enough.

In C doing that would be pointless (or at least not that benefitial) because you cannot get rid of returning in case of error anyway, and that's why I think I have never seen that kind of approach mentioned in any discussions about error handling.

Is there any important pitfall in that approach of mine? Can errno be != 0 in surprising situations? Anything to be aware of? That fact that I have never seen this "approach" discussed anywhere makes me wonder if there's any good reason for it, because I don't see any.

NOTE: Of course, you have to be careful about functions that set errno in conditions that might be ok for you. Know the functions you use very well and don't let the habit of just calling ko cause you forget about checking the man pages of the functions you use, continuously.


Solution

  • You can not replace error checking with exceptions when wrapping C with C++. Per the (draft) C11 standard 7.5 Errors <errno.h>, paragraph 3:

    The value of errno in the initial thread is zero at program startup (the initial value of errno in other threads is an indeterminate value), but is never set to zero by any library function. The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in this International Standard.

    Note these two statements:

    [errno] ... is never set to zero by any library function.

    and.

    The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in this International Standard.

    So you can never rely on the value of errno unless you have already established you've received an error from a function that's documented to set errno.

    So you'd have to wrap all your C calls with C++ calls in ways that handle errors properly in order to turn them into exceptions.

    Nevermind relying on exceptions to handles expected conditions is widely considered a VERY bad practice. All files end - tossing an exception on EOF is a misuse of exceptions - it's in no way exceptional.