Как я могу напечатать символическое имя 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. Вероятно,вы могли бы достаточно легко сократить его до макроса, но для каждой ошибки необходимо создать регистр.