Как я могу напечатать символическое имя errno в C?
Я могу использовать perror()
или strerror()
для печати сообщения об ошибке "читаемый человеком", принадлежащего errno
, а что если я и хотите напечатать символическое имя (например,"EAGAIN
") к errno
?
любая удобная функция или макрос, чтобы сделать это?
обновление: прикрепление кода я закончил писать, основываясь на идее принятого ответа ниже и его комментариях:
#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(, /^#[[: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 '' 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++] = '';
if (pclose(f) == -1) {
perror("Failed to pclose() in get_errno_name()");
return -1;
}
return read_size;
}
5 ответов
нет простого способа сделать это.
вы можете создать программу - и я создал ее, которая может быть переупакована как библиотечная функция-которая преобразует из числа в имя. Но генерировать таблицу умеренно сложно. Я использую скрипт Perl, который запускает компилятор (GCC или эквивалент) с параметрами (-H
), чтобы перечислить заголовки, которые включены, включая /usr/include/errno.h
, а затем сканирует эти файлы, ища имена (#define
плюс E
за ним следует прописная буква или цифра) цифры, и комментарии. Это работает на Linux, Mac OS X, Solaris, HP-UX, AIX. Это не так уж тривиально.
остерегайтесь,errno.h
на Mac OS X включает в себя имя ELAST
(имя, зарезервированное для реализации), которое является дубликатом самого высокого числа (но отображение изменяется от выпуска к выпуску; это было 105 в Mountain Lion, я считаю, но это 106 в Mavericks).
насколько мне известно, вы не можете. Некоторые целочисленные константы ошибок сопоставляются с несколькими символьными именами, например EAGAIN и EWOULDBLOCK. Очевидно, вы можете найти их на странице руководства команды, которая устанавливает errno.
если вы знаете, какие ошибки вы ожидаете, вы можете написать big switch/case
или if/else
блоки против errno
, в следующем виде:
if (errno == EAGAIN)
fprintf(stderr, "EAGAIN");
очевидная проблема с этим заключается в том, что если вы хотите конкретное имя errno, вам нужно написать против каждого возможного варианта, и их довольно много.
Я не знаю функции, которая делает это, но было бы нетрудно написать, если вы знакомы с ошибками, возвращаемыми в вашей программе.
вы можете написать строки, содержащие выходы strerror () и использовать цикл for и операторы if с strcmp () (который возвращает значение, основанное на успехе или неудаче), чтобы сравнить строки, которые вы написали. Если они одинаковы, вы можете вывести символьное имя* , если вы установите его в другую строку.
поскольку символьные имена хранятся в виде перечислений и C
относится к ним как Ints
. Вам нужно будет создать функцию, подобную этому so question как преобразовать имена перечислений в строку в c. Вероятно,вы могли бы достаточно легко сократить его до макроса, но для каждой ошибки необходимо создать регистр.