errno, And Error Handling#

errno Is A Global Variable#

  • errno is global, with all consequences

  • Should read it immediately after something went wrong

#include <fcntl.h>
#include <print>

int main()
{
    int fd = open("/etc/passwd", O_WRONLY);
    if (fd == -1) {
        std::println("open failed");                   // <-- might encounter an error, somewhere, internally
        std::println("errno=={}", errno);              // <-- errno might not be open's anymore
        return 1;
    }

    return 0;
}

Simplest Stringification: perror()#

  • Advantage: need not mention errno

  • Writes human-readable description of errno to standard error

  • Value of errno not printed though

#include <fcntl.h>
#include <stdio.h>

int main()
{
    int fd = open("/etc/passwd", O_WRONLY);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }

    return 0;
}
$ ./sysprog-errors--perror
open failed: Permission denied

More Stringification: strerror()#

  • Returns a pointer to a descriptive string

  • Does not print anything itself

  • Not thread-safe: pointer might be invalidated by subsequent calls to strerror()

  • Historical baggage: return type is char* - but please don’t write to it

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <print>

int main()
{
    int fd = open("/etc/passwd", O_WRONLY);
    if (fd == -1) {
        const char* errstr = strerror(errno);
        std::println("open failed: {} ({})", errstr, errno);
        return 1;
    }

    return 0;
}
$ ./sysprog-errors--strerror
open failed: Permission denied (13)

Thread-Safe Stringification: strerror_r()#

  • _r for “reentrant”

  • User has to supply buffer

  • Buffer might be used by strerror_r()

  • Message might be truncated if buffer too small; always 0-terminated

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <print>

int main()
{
    int fd = open("/etc/passwd", O_WRONLY);
    if (fd == -1) {
        char buf[64];                                  // <-- *might* be used
        const char* errstr = strerror_r(errno, buf, sizeof(buf));
        std::println("open failed: {} ({})", errstr, errno);
        return 1;
    }

    return 0;
}
$ ./sysprog-errors--strerror_r
open failed: Permission denied (13)