Как конвертировать errno в UNIX в соответствующую строку?

Есть ли в UNIX какая-либо функция для преобразования errno в соответствующую ей строку, например, для EIDRM в "EIDRM". Очень неприятно отлаживать проверку на наличие ошибок с этими целочисленными ошибками.

5 ответов

Решение

strerror() должен сделать это. http://linux.die.net/man/3/strerror

К вашему сведению, чтобы вы могли легче находить эти вещи сами: если вы наберете man errno (или какую-либо функцию, которую вы исследуете) и посмотрите в самую нижнюю часть страницы руководства, вы увидите список связанных функций. если ты man каждый из них (предполагая, что делать первым, основываясь на их именах), вы часто найдете ответ на похожие вопросы.

Просто еще одно решение, которое решает именно вашу проблему, но в Python вместо C:

>>> import errno
>>> errno.errorcode[errno.EIDRM]
'EIDRM'

Теперь есть утилита errno, распространяемая с пакетом moreutils.

Я не уверен в таком enum имен стилей, но для целей отладки и отчетов об ошибках вы можете использовать perror(3) или же strerror(3) Функции на Си, которые возвращают читабельное представление кода ошибки. Пожалуйста, обратитесь к справочным страницам для более подробной информации.

Если вы действительно хотите EIDRM, а не строку ошибки: нет. Тем не менее, на OpenBSD,

man errno|egrep ' [0-9]+ E[A-Z]+'|sed 's/^ *//'|cut -d' ' -f1,2

распечатывает красивую таблицу "...\n89 EIDM\n...", которую вы можете преобразовать далее в структуру данных для языка программирования, в котором вы хотели бы иметь эту функцию.

В UNIX нет стандартной функции для этого.

Но я недавно писал errnonameбиблиотека, имеющаяerrnoname функция, которая делает именно это.

strerror (также strerror_r, strerror_l, perror) напечатайте "дружественную к человеку" подсказку о том, в чем была ошибка, но их результаты

  • обычно без документов,
  • не стандартизирован,
  • не гарантируется соблюдение каких-либо ограничений по длине или формату,
  • часто отличается в зависимости от настроек локали и
  • не всегда имеют смысл во всех ситуациях (например, они обычно печатают File exists за EEXIST, хотя эта ошибка часто возвращается для вещей, которые не являются файлами).

Это означает, что они внешне удобны, но

  • другой код не может анализировать их как надежно (хуже для автоматизации, мониторинга, создания сценариев, программ-оболочек и т. д.),
  • может ввести в заблуждение в крайних случаях, и
  • встать на пути опытных пользователей.

По иронии судьбы, ничто не мешает этим функциям просто использоватьerrno символическое имя в качестве строки ошибки при любых обстоятельствах - оно будет в пределах буквы стандарта, особенно если они сделали это только для определенной локали, например, специальной Cлокаль. Но ни одна из известных мне libc не делает этого.

Во всяком случае, поскольку мой errnoname выпущен под "лицензией BSD без оговорок" (0BSD), которая является разрешительной лицензией или, точнее, лицензией, эквивалентной общедоступной, вы можете делать с ней все, что захотите.

Чтобы сделать этот ответ самобытным, но при этом уместным в пределах количества символов ответа, ниже приведены два сокращенных варианта errnoname функция.

В errnoname они оба реализованы, но здесь я выделил суть каждого, чтобы сделать их более удобочитаемыми.

Пара примечаний:

  1. Это охватывает все или большую часть errno имена для Linux, Darwin (Mac OS X и iOS X), FreeBSD, NetBSD, OpenBSD, DragonflyBSD и нескольких Unix с закрытым исходным кодом по состоянию на начало января 2020 года.

  2. Он возвращает нулевой указатель, если вы дадите ему errno значение, которое ему неизвестно.

Вариант 1: простой, универсальный

Этот очень портативный и простой, не о чем беспокоиться. Он будет компилироваться практически с любым компилятором C89 или лучше, который вы можете использовать. (Возможно, даже компиляторы C++, что становится все реже по мере расхождения языков.)

Этот вариант может компилироваться в очень эффективный код (поиск в массиве вместо оператора switch) на современных компиляторах, когда оптимизация достаточно высока, но может не зависеть от конкретной ситуации.

#include <errno.h>

char const * errnoname(int errno_)
{
    switch(errno_)
    {
#ifdef E2BIG
        case E2BIG: return "E2BIG";
#endif
#ifdef EACCES
        case EACCES: return "EACCES";
#endif
/*
    repeat for the other 100+ errno names,
    don't forget to handle possible duplicates
    like EAGAIN and EWOULDBLOCK
*/
    }
    return 0;
}

Вариант 2: явно эффективный, подходит для большинства систем

Это один более очевидно эффективный, и будет компилировать эффективный код очень надежно, потому что это делает массив поиска явным и не зависит от компьютера оптимизаций.

Это безопасно, если в системе есть положительные, относительно небольшие и достаточно смежные errno ценности.

Может компилироваться только на компиляторах, которые реализуют назначенные не по порядку инициализаторы для массивов (C99 или лучше, за исключением всех версий C++ на данный момент).

#include <errno.h>

char const * errnoname(int errno_)
{
    static char const * const names[] =
    {
#ifdef E2BIG
        [E2BIG] = "E2BIG",
#endif
#ifdef EACCES
        [EACCES] = "EACCES",
#endif
/*
    repeat for the other 100+ errno names,
    don't forget to handle possible duplicates
    like EAGAIN and EWOULDBLOCK
*/
    };
    if(errno_ >= 0 && errno_ < (sizeof(names) / sizeof(*names)))
    {
        return names[errno_];
    }
    return 0;
}
Другие вопросы по тегам