errno, And Error Handling#
errno Is A Global Variable#
errnois global, with all consequencesShould 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
errnoWrites human-readable description of
errnoto standard errorValue of
errnonot 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()#
_rfor “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)