I can use perror()
or strerror()
to print the "human readable" error message belonging to an errno
, but what if I also want to print the symbolic name (e.g., "EAGAIN
") of the errno
?
Any convenient function or macro to do that?
Re-edit from the future: You're better off using the strerrorname_np()
recently added to glibc (see accepted answer), or the errnoname
library (previously accepted answer), rather than this hacky code I came up with before those options existed:
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
int get_errno_name(char *buf, int buf_size) {
// Using the linux-only gawk instead of awk, because of the convenient
// match() functionality. For Posix portability, use a different recipe...
char cmd[] = "e= && " // errno to be inserted here (max digits = 6)
"echo '#include <errno.h>' | "
"gcc -dM -E - | " // optionally, use $CC inead of gcc
"gawk \"match(\\$0, /^#[[:space:]]*define[[:space:]]+"
"(E[[:alnum:]]+)[[:space:]]+$e($|[^[:alnum:]])/, m) "
"{ print m[1] }\"";
{
// Insert the errno as the "e" shell variable in the command above.
int errno_digit_c = snprintf(cmd + 2, 6, "%d", errno);
if (errno_digit_c < 1) {
fprintf(stderr, "Failed to stringify an errno "
"in get_errno_name().\n");
return -1;
}
// Replace the inserted terminating '\0' with whitespace
cmd[errno_digit_c + 2] = ' ';
}
FILE *f = popen(cmd, "r");
if (f == NULL) {
perror("Failed to popen() in get_errno_name()");
return -1;
}
int read_size = 0, c;
while ((c = getc(f)) != EOF) {
if (isalnum(c)) {
buf[read_size++] = c;
if (read_size + 1 > buf_size) {
fprintf(stderr, "Read errno name is larger than the character "
"buffer supplied to get_errno_name().\n");
return -1;
}
}
}
buf[read_size++] = '\0';
if (pclose(f) == -1) {
perror("Failed to pclose() in get_errno_name()");
return -1;
}
return read_size;
}
glibc provides a function for that (a GNU extension): strerrorname_np()
.
It is declared in <string.h>
.
It returns the errno
name for valid values, or NULL
for invalid ones.
It was added in glibc 2.32.