Преобразование целого числа errno POSIX в константу времени компиляции

Иногда (например, используя strace, gdb и т. Д.) Обнаруживается, что вызов POSIX устанавливает errno в целочисленное значение, и нужно знать константу C времени компиляции (более точно определение препроцессора), чтобы проверить ее (например, ECHILD) - см., Например, waitpid для дочернего процесса не выполняется.

Например, в приведенном выше вопросе целочисленный номер ошибки 10 был возвращен в errno. Я хочу вернуться от этого к строке ECHILD. Не то, что perror или strerror дали бы мне («Никаких дочерних процессов» или подобное).

Вот очевидный способ сделать это, но он не работает:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main (int argc, char **argv)
{
  printf ("%s\n", strerror (10));
  exit (0);
}

Это печатает вывод:

No child processes

не ECHILD, следовательно, не делает требуемого.

Есть ли более простой способ сделать это, чем несколько ручное руководство с grep по /usr/include?

Вы можете подумать, что это дубликаты, но на самом деле это не так:

Соответствующий ответ может включать некоторую магию для предварительной обработки соответствующих частей /usr/include и отображения любых констант, начинающихся с E, с соответствующим значением.


person abligh    schedule 04.05.2015    source источник
comment
Вопрос немного непонятный. Вы имеете в виду, что с учетом значения int ECHILD вам нужно / name / этого символа ECHILD?   -  person BadZen    schedule 04.05.2015
comment
@BadZen - именно так. Я уточню.   -  person abligh    schedule 04.05.2015
comment
@cdarke - я думаю, что один похож на второй, который я упомянул - мне не нужно делать это на C.   -  person abligh    schedule 05.05.2015


Ответы (11)


Вы можете вызвать препроцессор C. Для инструментальной цепочки GCC исполняемый файл препроцессора - cpp.

(Изменить: я понимаю, что вы специально упомянули POSIX, и этот пример относится к GCC, но, возможно, это только начало)

Вот пример, который я придумал для вашей ситуации:

$ cpp -dM -include /usr/include/errno.h | grep '^#define E' | sed 's/^#define \(E[A-Z0-9]*\)\s*\(.*\)$/\2 \1/g' | sort -n
EAGAIN EWOULDBLOCK
EDEADLK EDEADLOCK
EOPNOTSUPP ENOTSUP
1 EPERM
2 ENOENT
3 ESRCH
4 EINTR
5 EIO
6 ENXIO
7 E2BIG
8 ENOEXEC
9 EBADF
10 ECHILD
11 EAGAIN
12 ENOMEM
13 EACCES
14 EFAULT
15 ENOTBLK
16 EBUSY
17 EEXIST
18 EXDEV
19 ENODEV
20 ENOTDIR
21 EISDIR
22 EINVAL
23 ENFILE
24 EMFILE
25 ENOTTY
26 ETXTBSY
27 EFBIG
28 ENOSPC
29 ESPIPE
30 EROFS
31 EMLINK
32 EPIPE
33 EDOM
34 ERANGE
35 EDEADLK
36 ENAMETOOLONG
37 ENOLCK
38 ENOSYS
39 ENOTEMPTY
40 ELOOP
42 ENOMSG
43 EIDRM
44 ECHRNG
45 EL2NSYNC
46 EL3HLT
47 EL3RST
48 ELNRNG
49 EUNATCH
50 ENOCSI
51 EL2HLT
52 EBADE
53 EBADR
54 EXFULL
55 ENOANO
56 EBADRQC
57 EBADSLT
59 EBFONT
60 ENOSTR
61 ENODATA
62 ETIME
63 ENOSR
64 ENONET
65 ENOPKG
66 EREMOTE
67 ENOLINK
68 EADV
69 ESRMNT
70 ECOMM
71 EPROTO
72 EMULTIHOP
73 EDOTDOT
74 EBADMSG
75 EOVERFLOW
76 ENOTUNIQ
77 EBADFD
78 EREMCHG
79 ELIBACC
80 ELIBBAD
81 ELIBSCN
82 ELIBMAX
83 ELIBEXEC
84 EILSEQ
85 ERESTART
86 ESTRPIPE
87 EUSERS
88 ENOTSOCK
89 EDESTADDRREQ
90 EMSGSIZE
91 EPROTOTYPE
92 ENOPROTOOPT
93 EPROTONOSUPPORT
94 ESOCKTNOSUPPORT
95 EOPNOTSUPP
96 EPFNOSUPPORT
97 EAFNOSUPPORT
98 EADDRINUSE
99 EADDRNOTAVAIL
100 ENETDOWN
101 ENETUNREACH
102 ENETRESET
103 ECONNABORTED
104 ECONNRESET
105 ENOBUFS
106 EISCONN
107 ENOTCONN
108 ESHUTDOWN
109 ETOOMANYREFS
110 ETIMEDOUT
111 ECONNREFUSED
112 EHOSTDOWN
113 EHOSTUNREACH
114 EALREADY
115 EINPROGRESS
116 ESTALE
117 EUCLEAN
118 ENOTNAM
119 ENAVAIL
120 EISNAM
121 EREMOTEIO
122 EDQUOT
123 ENOMEDIUM
124 EMEDIUMTYPE
125 ECANCELED
126 ENOKEY
127 EKEYEXPIRED
128 EKEYREVOKED
129 EKEYREJECTED
130 EOWNERDEAD
131 ENOTRECOVERABLE
132 ERFKILL
133 EHWPOISON

Несколько замечаний:

  • Это почти наверняка не надежно. Весьма вероятно, что он упустит некоторые вещи, а в других сделает ошибку. Во-первых, если есть другие определения макросов в любом файле #include-ed (прямо или косвенно) от errno.h, то возможно, что grep '^#define E' недостаточно для фильтрации желаемых errno определений. из вывода команды cpp. И это отнюдь не единственный вариант, при котором такой подход может потерпеть неудачу.
  • Очевидно, есть случаи, такие как #define EWOULDBLOCK EAGAIN, где одно значение Exxxx определяется как синоним другого ранее определенного значения.
  • Похоже, что в последовательности есть некоторые пропущенные значения, например 41. Я не уверен, нормально ли это или это пример чего-то, чего не хватает при таком подходе.

Убрав эти заявления об отказе от ответственности, должна быть возможность использовать этот подход в качестве основы для сценария (который затем можно было бы при желании вызвать из своего Makefile) для автоматического создания таблицы поиска (например, errno-lookup.c) и ссылки на эту таблицу в ваш код, чтобы получить связанный символ для любого заданного значения errno.

person Mike Holt    schedule 04.05.2015

Набор констант EFOO, определенных (прямо или косвенно) в <errno.h>, и их значений варьируется от одной системы к другой. И часто более чем одна EFOO константа будет иметь; например, в моей системе и EAGAIN, и EWOULDBLOCK имеют значение 11. Таким образом, не обязательно иметь уникальный EFOO символ для данного числового errno значения.

Я собрал список из 160 E* символов из разных систем. Он не является ни окончательным, ни исчерпывающим. Вы можете написать сценарий, который принимает список в качестве входных данных и генерирует исходную программу на C, которая печатает числовое значение каждого символа. Для каждого символа программа будет содержать что-то вроде:

#ifdef E2BIG
    printf("E2BIG %d\n", E2BIG);
#endif

Из этого вы можете сгенерировать функцию C, которая возвращает соответствующий символ в виде строки или что-то вроде "?", если такого символа нет.

Я знаю, что это неполный ответ, но это хорошая отправная точка. Позже я могу реализовать более полное решение. Если это так, я, вероятно, создам его как проект Github и обновлю этот ответ ссылкой на него.

Вот список:

E2BIG EACCES EADDRINUSE EADDRNOTAVAIL EADV EAFNOSUPPORT EAGAIN
EALREADY EBADCOOKIE EBADE EBADF EBADFD EBADHANDLE EBADMSG EBADR EBADRQC
EBADSLT EBADTYPE EBFONT EBUSY ECANCELED ECANCELLED ECHILD ECHRNG ECOMM
ECONNABORTED ECONNREFUSED ECONNRESET EDEADLK EDEADLOCK EDESTADDRREQ
EDOM EDOTDOT EDQUOT EEXIST EFAULT EFBIG EHOSTDOWN EHOSTUNREACH EHWPOISON
EIDRM EILSEQ EINIT EINPROGRESS EINTR EINVAL EIO EIOCBQUEUED EIOCBRETRY
EISCONN EISDIR EISNAM EJUKEBOX EKEYEXPIRED EKEYREJECTED EKEYREVOKED
EL2HLT EL2NSYNC EL3HLT EL3RST ELIBACC ELIBBAD ELIBEXEC ELIBMAX ELIBSCN
ELNRNG ELOCKUNMAPPED ELOOP EMAXERRNO EMEDIUMTYPE EMFILE EMLINK EMSGSIZE
EMULTIHOP ENAMETOOLONG ENAVAIL ENETDOWN ENETRESET ENETUNREACH ENFILE
ENOANO ENOBUFS ENOCSI ENODATA ENODEV ENOENT ENOEXEC ENOIOCTLCMD ENOKEY
ENOLCK ENOLINK ENOMEDIUM ENOMEM ENOMSG ENONET ENOPKG ENOPROTOOPT ENOSPC
ENOSR ENOSTR ENOSYM ENOSYS ENOTACTIVE ENOTBLK ENOTCONN ENOTDIR ENOTEMPTY
ENOTNAM ENOTRECOVERABLE ENOTSOCK ENOTSUP ENOTSUPP ENOTSYNC ENOTTY
ENOTUNIQ ENXIO EOPNOTSUPP EOVERFLOW EOWNERDEAD EPERM EPFNOSUPPORT EPIPE
EPROCLIM EPROTO EPROTONOSUPPORT EPROTOTYPE ERANGE EREFUSED EREMCHG EREMDEV
EREMOTE EREMOTEIO EREMOTERELEASE ERESTART ERESTARTNOHAND ERESTARTNOINTR
ERESTARTSYS ERESTART_RESTARTBLOCK ERFKILL EROFS ERREMOTE ESERVERFAULT
ESHUTDOWN ESOCKTNOSUPPORT ESPIPE ESRCH ESRMNT ESTALE ESTRPIPE ETIME
ETIMEDOUT ETOOMANYREFS ETOOSMALL ETXTBSY EUCLEAN EUNATCH EUSERS
EWOULDBLOCK EXDEV EXFULL
person Keith Thompson    schedule 04.05.2015

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

Таким образом, вы можете взять свой пример программы из вопроса #include "errnoname.h", просто замените strerror на errnoname и скомпилируйте / скомпилируйте его с errnoname.c.

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

Примеры:

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

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

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

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

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

#include <errno.h>

char const * errnoname(int errno_)
{
    switch(errno_)
    {
#ifdef E2BIG
        case E2BIG: return "E2BIG";
#endif
#ifdef EACCES
        case EACCES: return "EACCES";
#endif
#ifdef EADDRINUSE
        case EADDRINUSE: return "EADDRINUSE";
#endif
#ifdef EADDRNOTAVAIL
        case EADDRNOTAVAIL: return "EADDRNOTAVAIL";
#endif
#ifdef EADI
        case EADI: return "EADI";
#endif
#ifdef EADV
        case EADV: return "EADV";
#endif
#ifdef EAFNOSUPPORT
        case EAFNOSUPPORT: return "EAFNOSUPPORT";
#endif
#ifdef EAGAIN
        case EAGAIN: return "EAGAIN";
#endif
#ifdef EAIO
        case EAIO: return "EAIO";
#endif
#ifdef EALIGN
        case EALIGN: return "EALIGN";
#endif
#ifdef EALREADY
        case EALREADY: return "EALREADY";
#endif
#ifdef EASYNC
        case EASYNC: return "EASYNC";
#endif
#ifdef EAUTH
        case EAUTH: return "EAUTH";
#endif
#ifdef EBADARCH
        case EBADARCH: return "EBADARCH";
#endif
#ifdef EBADE
        case EBADE: return "EBADE";
#endif
#ifdef EBADEXEC
        case EBADEXEC: return "EBADEXEC";
#endif
#ifdef EBADF
        case EBADF: return "EBADF";
#endif
#ifdef EBADFD
        case EBADFD: return "EBADFD";
#endif
#ifdef EBADMACHO
        case EBADMACHO: return "EBADMACHO";
#endif
#ifdef EBADMSG
        case EBADMSG: return "EBADMSG";
#endif
#ifdef EBADR
        case EBADR: return "EBADR";
#endif
#ifdef EBADRPC
        case EBADRPC: return "EBADRPC";
#endif
#ifdef EBADRQC
        case EBADRQC: return "EBADRQC";
#endif
#ifdef EBADSLT
        case EBADSLT: return "EBADSLT";
#endif
#ifdef EBADVER
        case EBADVER: return "EBADVER";
#endif
#ifdef EBFONT
        case EBFONT: return "EBFONT";
#endif
#ifdef EBUSY
        case EBUSY: return "EBUSY";
#endif
#ifdef ECANCELED
        case ECANCELED: return "ECANCELED";
#endif
#if defined(ECANCELLED) && (!defined(ECANCELED) || ECANCELLED != ECANCELED)
        case ECANCELLED: return "ECANCELLED";
#endif
#ifdef ECAPMODE
        case ECAPMODE: return "ECAPMODE";
#endif
#ifdef ECHILD
        case ECHILD: return "ECHILD";
#endif
#ifdef ECHRNG
        case ECHRNG: return "ECHRNG";
#endif
#ifdef ECKPT
        case ECKPT: return "ECKPT";
#endif
#ifdef ECLONEME
        case ECLONEME: return "ECLONEME";
#endif
#ifdef ECOMM
        case ECOMM: return "ECOMM";
#endif
#ifdef ECONFIG
        case ECONFIG: return "ECONFIG";
#endif
#ifdef ECONNABORTED
        case ECONNABORTED: return "ECONNABORTED";
#endif
#ifdef ECONNREFUSED
        case ECONNREFUSED: return "ECONNREFUSED";
#endif
#ifdef ECONNRESET
        case ECONNRESET: return "ECONNRESET";
#endif
#ifdef ECORRUPT
        case ECORRUPT: return "ECORRUPT";
#endif
#ifdef ECVCERORR
        case ECVCERORR: return "ECVCERORR";
#endif
#ifdef ECVPERORR
        case ECVPERORR: return "ECVPERORR";
#endif
#ifdef EDEADLK
        case EDEADLK: return "EDEADLK";
#endif
#if defined(EDEADLOCK) && (!defined(EDEADLK) || EDEADLOCK != EDEADLK)
        case EDEADLOCK: return "EDEADLOCK";
#endif
#ifdef EDESTADDREQ
        case EDESTADDREQ: return "EDESTADDREQ";
#endif
#ifdef EDESTADDRREQ
        case EDESTADDRREQ: return "EDESTADDRREQ";
#endif
#ifdef EDEVERR
        case EDEVERR: return "EDEVERR";
#endif
#ifdef EDIRIOCTL
        case EDIRIOCTL: return "EDIRIOCTL";
#endif
#ifdef EDIRTY
        case EDIRTY: return "EDIRTY";
#endif
#ifdef EDIST
        case EDIST: return "EDIST";
#endif
#ifdef EDOM
        case EDOM: return "EDOM";
#endif
#ifdef EDOOFUS
        case EDOOFUS: return "EDOOFUS";
#endif
#ifdef EDOTDOT
        case EDOTDOT: return "EDOTDOT";
#endif
#ifdef EDQUOT
        case EDQUOT: return "EDQUOT";
#endif
#ifdef EDUPFD
        case EDUPFD: return "EDUPFD";
#endif
#ifdef EDUPPKG
        case EDUPPKG: return "EDUPPKG";
#endif
#ifdef EEXIST
        case EEXIST: return "EEXIST";
#endif
#ifdef EFAIL
        case EFAIL: return "EFAIL";
#endif
#ifdef EFAULT
        case EFAULT: return "EFAULT";
#endif
#ifdef EFBIG
        case EFBIG: return "EFBIG";
#endif
#ifdef EFORMAT
        case EFORMAT: return "EFORMAT";
#endif
#ifdef EFSCORRUPTED
        case EFSCORRUPTED: return "EFSCORRUPTED";
#endif
#ifdef EFTYPE
        case EFTYPE: return "EFTYPE";
#endif
#ifdef EHOSTDOWN
        case EHOSTDOWN: return "EHOSTDOWN";
#endif
#ifdef EHOSTUNREACH
        case EHOSTUNREACH: return "EHOSTUNREACH";
#endif
#ifdef EHWPOISON
        case EHWPOISON: return "EHWPOISON";
#endif
#ifdef EIDRM
        case EIDRM: return "EIDRM";
#endif
#ifdef EILSEQ
        case EILSEQ: return "EILSEQ";
#endif
#ifdef EINIT
        case EINIT: return "EINIT";
#endif
#ifdef EINPROG
        case EINPROG: return "EINPROG";
#endif
#ifdef EINPROGRESS
        case EINPROGRESS: return "EINPROGRESS";
#endif
#ifdef EINTEGRITY
        case EINTEGRITY: return "EINTEGRITY";
#endif
#ifdef EINTR
        case EINTR: return "EINTR";
#endif
#ifdef EINVAL
        case EINVAL: return "EINVAL";
#endif
#ifdef EIO
        case EIO: return "EIO";
#endif
#ifdef EIPSEC
        case EIPSEC: return "EIPSEC";
#endif
#ifdef EISCONN
        case EISCONN: return "EISCONN";
#endif
#ifdef EISDIR
        case EISDIR: return "EISDIR";
#endif
#ifdef EISNAM
        case EISNAM: return "EISNAM";
#endif
#ifdef EJUSTRETURN
        case EJUSTRETURN: return "EJUSTRETURN";
#endif
#ifdef EKEEPLOOKING
        case EKEEPLOOKING: return "EKEEPLOOKING";
#endif
#ifdef EKEYEXPIRED
        case EKEYEXPIRED: return "EKEYEXPIRED";
#endif
#ifdef EKEYREJECTED
        case EKEYREJECTED: return "EKEYREJECTED";
#endif
#ifdef EKEYREVOKED
        case EKEYREVOKED: return "EKEYREVOKED";
#endif
#ifdef EL2HLT
        case EL2HLT: return "EL2HLT";
#endif
#ifdef EL2NSYNC
        case EL2NSYNC: return "EL2NSYNC";
#endif
#ifdef EL3HLT
        case EL3HLT: return "EL3HLT";
#endif
#ifdef EL3RST
        case EL3RST: return "EL3RST";
#endif
#ifdef ELIBACC
        case ELIBACC: return "ELIBACC";
#endif
#ifdef ELIBBAD
        case ELIBBAD: return "ELIBBAD";
#endif
#ifdef ELIBEXEC
        case ELIBEXEC: return "ELIBEXEC";
#endif
#ifdef ELIBMAX
        case ELIBMAX: return "ELIBMAX";
#endif
#ifdef ELIBSCN
        case ELIBSCN: return "ELIBSCN";
#endif
#ifdef ELNRNG
        case ELNRNG: return "ELNRNG";
#endif
#ifdef ELOCKUNMAPPED
        case ELOCKUNMAPPED: return "ELOCKUNMAPPED";
#endif
#ifdef ELOOP
        case ELOOP: return "ELOOP";
#endif
#ifdef EMEDIA
        case EMEDIA: return "EMEDIA";
#endif
#ifdef EMEDIUMTYPE
        case EMEDIUMTYPE: return "EMEDIUMTYPE";
#endif
#ifdef EMFILE
        case EMFILE: return "EMFILE";
#endif
#ifdef EMLINK
        case EMLINK: return "EMLINK";
#endif
#ifdef EMOUNTEXIT
        case EMOUNTEXIT: return "EMOUNTEXIT";
#endif
#ifdef EMOVEFD
        case EMOVEFD: return "EMOVEFD";
#endif
#ifdef EMSGSIZE
        case EMSGSIZE: return "EMSGSIZE";
#endif
#ifdef EMTIMERS
        case EMTIMERS: return "EMTIMERS";
#endif
#ifdef EMULTIHOP
        case EMULTIHOP: return "EMULTIHOP";
#endif
#ifdef ENAMETOOLONG
        case ENAMETOOLONG: return "ENAMETOOLONG";
#endif
#ifdef ENAVAIL
        case ENAVAIL: return "ENAVAIL";
#endif
#ifdef ENEEDAUTH
        case ENEEDAUTH: return "ENEEDAUTH";
#endif
#ifdef ENETDOWN
        case ENETDOWN: return "ENETDOWN";
#endif
#ifdef ENETRESET
        case ENETRESET: return "ENETRESET";
#endif
#ifdef ENETUNREACH
        case ENETUNREACH: return "ENETUNREACH";
#endif
#ifdef ENFILE
        case ENFILE: return "ENFILE";
#endif
#ifdef ENFSREMOTE
        case ENFSREMOTE: return "ENFSREMOTE";
#endif
#ifdef ENOANO
        case ENOANO: return "ENOANO";
#endif
#ifdef ENOATTR
        case ENOATTR: return "ENOATTR";
#endif
#ifdef ENOBUFS
        case ENOBUFS: return "ENOBUFS";
#endif
#ifdef ENOCONNECT
        case ENOCONNECT: return "ENOCONNECT";
#endif
#ifdef ENOCSI
        case ENOCSI: return "ENOCSI";
#endif
#ifdef ENODATA
        case ENODATA: return "ENODATA";
#endif
#ifdef ENODEV
        case ENODEV: return "ENODEV";
#endif
#ifdef ENOENT
        case ENOENT: return "ENOENT";
#endif
#ifdef ENOEXEC
        case ENOEXEC: return "ENOEXEC";
#endif
#ifdef ENOIOCTL
        case ENOIOCTL: return "ENOIOCTL";
#endif
#ifdef ENOKEY
        case ENOKEY: return "ENOKEY";
#endif
#ifdef ENOLCK
        case ENOLCK: return "ENOLCK";
#endif
#ifdef ENOLINK
        case ENOLINK: return "ENOLINK";
#endif
#ifdef ENOLOAD
        case ENOLOAD: return "ENOLOAD";
#endif
#ifdef ENOMATCH
        case ENOMATCH: return "ENOMATCH";
#endif
#ifdef ENOMEDIUM
        case ENOMEDIUM: return "ENOMEDIUM";
#endif
#ifdef ENOMEM
        case ENOMEM: return "ENOMEM";
#endif
#ifdef ENOMSG
        case ENOMSG: return "ENOMSG";
#endif
#ifdef ENONET
        case ENONET: return "ENONET";
#endif
#ifdef ENOPKG
        case ENOPKG: return "ENOPKG";
#endif
#ifdef ENOPOLICY
        case ENOPOLICY: return "ENOPOLICY";
#endif
#ifdef ENOPROTOOPT
        case ENOPROTOOPT: return "ENOPROTOOPT";
#endif
#ifdef ENOREG
        case ENOREG: return "ENOREG";
#endif
#ifdef ENOSPC
        case ENOSPC: return "ENOSPC";
#endif
#ifdef ENOSR
        case ENOSR: return "ENOSR";
#endif
#ifdef ENOSTR
        case ENOSTR: return "ENOSTR";
#endif
#ifdef ENOSYM
        case ENOSYM: return "ENOSYM";
#endif
#ifdef ENOSYS
        case ENOSYS: return "ENOSYS";
#endif
#ifdef ENOTACTIVE
        case ENOTACTIVE: return "ENOTACTIVE";
#endif
#ifdef ENOTBLK
        case ENOTBLK: return "ENOTBLK";
#endif
#ifdef ENOTCAPABLE
        case ENOTCAPABLE: return "ENOTCAPABLE";
#endif
#ifdef ENOTCONN
        case ENOTCONN: return "ENOTCONN";
#endif
#ifdef ENOTDIR
        case ENOTDIR: return "ENOTDIR";
#endif
#ifdef ENOTEMPTY
        case ENOTEMPTY: return "ENOTEMPTY";
#endif
#ifdef ENOTNAM
        case ENOTNAM: return "ENOTNAM";
#endif
#ifdef ENOTREADY
        case ENOTREADY: return "ENOTREADY";
#endif
#ifdef ENOTRECOVERABLE
        case ENOTRECOVERABLE: return "ENOTRECOVERABLE";
#endif
#ifdef ENOTRUST
        case ENOTRUST: return "ENOTRUST";
#endif
#ifdef ENOTSOCK
        case ENOTSOCK: return "ENOTSOCK";
#endif
#ifdef ENOTSUP
        case ENOTSUP: return "ENOTSUP";
#endif
#ifdef ENOTTY
        case ENOTTY: return "ENOTTY";
#endif
#ifdef ENOTUNIQ
        case ENOTUNIQ: return "ENOTUNIQ";
#endif
#ifdef ENOUNLD
        case ENOUNLD: return "ENOUNLD";
#endif
#ifdef ENOUNREG
        case ENOUNREG: return "ENOUNREG";
#endif
#ifdef ENXIO
        case ENXIO: return "ENXIO";
#endif
#ifdef EOPCOMPLETE
        case EOPCOMPLETE: return "EOPCOMPLETE";
#endif
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || EOPNOTSUPP != ENOTSUP)
        case EOPNOTSUPP: return "EOPNOTSUPP";
#endif
#ifdef EOVERFLOW
        case EOVERFLOW: return "EOVERFLOW";
#endif
#ifdef EOWNERDEAD
        case EOWNERDEAD: return "EOWNERDEAD";
#endif
#ifdef EPASSTHROUGH
        case EPASSTHROUGH: return "EPASSTHROUGH";
#endif
#ifdef EPATHREMOTE
        case EPATHREMOTE: return "EPATHREMOTE";
#endif
#ifdef EPERM
        case EPERM: return "EPERM";
#endif
#ifdef EPFNOSUPPORT
        case EPFNOSUPPORT: return "EPFNOSUPPORT";
#endif
#ifdef EPIPE
        case EPIPE: return "EPIPE";
#endif
#ifdef EPOWERF
        case EPOWERF: return "EPOWERF";
#endif
#ifdef EPROCLIM
        case EPROCLIM: return "EPROCLIM";
#endif
#ifdef EPROCUNAVAIL
        case EPROCUNAVAIL: return "EPROCUNAVAIL";
#endif
#ifdef EPROGMISMATCH
        case EPROGMISMATCH: return "EPROGMISMATCH";
#endif
#ifdef EPROGUNAVAIL
        case EPROGUNAVAIL: return "EPROGUNAVAIL";
#endif
#ifdef EPROTO
        case EPROTO: return "EPROTO";
#endif
#ifdef EPROTONOSUPPORT
        case EPROTONOSUPPORT: return "EPROTONOSUPPORT";
#endif
#ifdef EPROTOTYPE
        case EPROTOTYPE: return "EPROTOTYPE";
#endif
#ifdef EPWROFF
        case EPWROFF: return "EPWROFF";
#endif
#ifdef EQFULL
        case EQFULL: return "EQFULL";
#endif
#ifdef EQSUSPENDED
        case EQSUSPENDED: return "EQSUSPENDED";
#endif
#ifdef ERANGE
        case ERANGE: return "ERANGE";
#endif
#ifdef ERECYCLE
        case ERECYCLE: return "ERECYCLE";
#endif
#ifdef EREDRIVEOPEN
        case EREDRIVEOPEN: return "EREDRIVEOPEN";
#endif
#ifdef EREFUSED
        case EREFUSED: return "EREFUSED";
#endif
#ifdef ERELOC
        case ERELOC: return "ERELOC";
#endif
#ifdef ERELOCATED
        case ERELOCATED: return "ERELOCATED";
#endif
#ifdef ERELOOKUP
        case ERELOOKUP: return "ERELOOKUP";
#endif
#ifdef EREMCHG
        case EREMCHG: return "EREMCHG";
#endif
#ifdef EREMDEV
        case EREMDEV: return "EREMDEV";
#endif
#ifdef EREMOTE
        case EREMOTE: return "EREMOTE";
#endif
#ifdef EREMOTEIO
        case EREMOTEIO: return "EREMOTEIO";
#endif
#ifdef EREMOTERELEASE
        case EREMOTERELEASE: return "EREMOTERELEASE";
#endif
#ifdef ERESTART
        case ERESTART: return "ERESTART";
#endif
#ifdef ERFKILL
        case ERFKILL: return "ERFKILL";
#endif
#ifdef EROFS
        case EROFS: return "EROFS";
#endif
#ifdef ERPCMISMATCH
        case ERPCMISMATCH: return "ERPCMISMATCH";
#endif
#ifdef ESAD
        case ESAD: return "ESAD";
#endif
#ifdef ESHLIBVERS
        case ESHLIBVERS: return "ESHLIBVERS";
#endif
#ifdef ESHUTDOWN
        case ESHUTDOWN: return "ESHUTDOWN";
#endif
#ifdef ESOCKTNOSUPPORT
        case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
#endif
#ifdef ESOFT
        case ESOFT: return "ESOFT";
#endif
#ifdef ESPIPE
        case ESPIPE: return "ESPIPE";
#endif
#ifdef ESRCH
        case ESRCH: return "ESRCH";
#endif
#ifdef ESRMNT
        case ESRMNT: return "ESRMNT";
#endif
#ifdef ESTALE
        case ESTALE: return "ESTALE";
#endif
#ifdef ESTART
        case ESTART: return "ESTART";
#endif
#ifdef ESTRPIPE
        case ESTRPIPE: return "ESTRPIPE";
#endif
#ifdef ESYSERROR
        case ESYSERROR: return "ESYSERROR";
#endif
#ifdef ETIME
        case ETIME: return "ETIME";
#endif
#ifdef ETIMEDOUT
        case ETIMEDOUT: return "ETIMEDOUT";
#endif
#ifdef ETOOMANYREFS
        case ETOOMANYREFS: return "ETOOMANYREFS";
#endif
#ifdef ETXTBSY
        case ETXTBSY: return "ETXTBSY";
#endif
#ifdef EUCLEAN
        case EUCLEAN: return "EUCLEAN";
#endif
#ifdef EUNATCH
        case EUNATCH: return "EUNATCH";
#endif
#ifdef EUSERS
        case EUSERS: return "EUSERS";
#endif
#ifdef EVERSION
        case EVERSION: return "EVERSION";
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || EWOULDBLOCK != EAGAIN)
        case EWOULDBLOCK: return "EWOULDBLOCK";
#endif
#ifdef EWRONGFS
        case EWRONGFS: return "EWRONGFS";
#endif
#ifdef EWRPROTECT
        case EWRPROTECT: return "EWRPROTECT";
#endif
#ifdef EXDEV
        case EXDEV: return "EXDEV";
#endif
#ifdef EXFULL
        case EXFULL: return "EXFULL";
#endif
    }
    return 0;
}
person mtraceur    schedule 11.08.2019

Вот мой собственный ответ, основанный на сочетании других и некоторых perl:

#!/usr/bin/perl
use strict;
use warnings;
die "Syntax: error ERRORNUM" unless ($#ARGV==0);
open (my $p, "cpp -dM /usr/include/errno.h |") || die ("Cannot preprocess headers: $!");
while (<$p>)
{
    chomp;
    print "$1\n" if /^#define (E\w+) (\d+)/ && $2==$ARGV[0];
}
close ($p);

Пример использования:

$ ./error 10
ECHILD

Я уверен, что это можно улучшить за счет обработки ошибок.

person abligh    schedule 04.05.2015

Вот трюк с Perl, который, кажется, делает это:

#!/usr/bin/perl -w
use strict;
no strict "refs";
use POSIX qw(:errno_h);

my $code = shift;

my $ns = \%{'POSIX::'};
foreach (keys %$ns) {
    print "$_\n" if /^E(?!XPORT)/ && (${$ns->{$_}}||-1) == $code;
}
person aschepler    schedule 04.05.2015
comment
Как мне это использовать? Это дает мне: Not a GLOB reference at ./e.pl line 10. (Ubuntu 14.04, perl v5.18.2) - person abligh; 05.05.2015
comment
Очевидно, что-то здесь отличается от старой версии Perl, которую я использовал, упс. - person aschepler; 05.05.2015
comment
Обновлено для Perl 5.20. - person aschepler; 05.05.2015
comment
Я обновил ваш ответ, поэтому он больше не печатает унифицированные предупреждения, когда ${$ns->{$_}} равно undef. Теперь отлично работает! - person abligh; 05.05.2015
comment
Также обратите внимание, что это единственный ответ, данный на сегодняшний день, который не требует синтаксического анализа включаемых файлов (возможно, ненадежно) или создания собственной таблицы. - person abligh; 05.05.2015

Функция strerror() обычно (всегда?) Предоставляет имя этой константы где-нибудь в возвращаемом сообщении. Это хитрость, но вы можете это сделать для первого непрерывного набора заглавных букв, начинающегося с 'E' ...

person BadZen    schedule 04.05.2015
comment
На самом деле, тестирование показывает, что я всегда / всегда был чрезвычайно оптимистичен. знак равно - person BadZen; 04.05.2015
comment
Однако они более или менее стандартны, поэтому, возможно, лучше всего подойдет реализация гигантского коммутатора с большим количеством case EPERM: { return "EPERM"; } и т. Д. - person BadZen; 04.05.2015
comment
Я никогда не знал, что это такое. Это не в том случае, о котором я упоминал (см. Вопрос). - person abligh; 04.05.2015
comment
Да, похоже, это не для кого-то из них - что заставляет меня думать, что я помню другую функцию, что strerror () ... - person BadZen; 04.05.2015

Сами символы можно использовать для составления таблицы символов ошибок. Очевидно, это требует, чтобы вы включили все заголовки, которые определяют константы, которые вы хотите учитывать.

Список констант копируется и вставляется из справочной страницы errno.

Если символ не известен в реализации ниже, записывается общий макрос, например ERROR_161. Если вам известен системный вызов, вызвавший код, поищите его документацию и вручную укажите возможные коды ошибок. Таким образом вы со временем создадите библиотеку кодов. (Согласен, это не очень элегантно.)

Коды создаются макросами и хранятся в виде статического массива строк с назначенными инициализаторами. Размер массива определяется наибольшим индексом.

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

// ... more sys includes as appropriate ...

#define ERRNAME(X) [X] = #X

static const char *errname[] = {
    ERRNAME(E2BIG),
    ERRNAME(EACCES),
    ERRNAME(EADDRINUSE),
    ERRNAME(EADDRNOTAVAIL),
    ERRNAME(EAFNOSUPPORT),
    ERRNAME(EAGAIN),
    // ... more symbols ...
};

const char *errsym(int e)
{
    static char buf[20];

    if (e >= 0 && e < (sizeof(errname) / sizeof(*errname))) {
        if (errname[e]) return errname[e];
    }

    snprintf(buf, sizeof(buf), "ERROR_%u", (unsigned int) e);
    return buf;
}
person M Oehm    schedule 04.05.2015
comment
Вы должны знать, что создание массива сопряжено с риском: 1) нет гарантии, что значения errno смежны или даже достаточно малы, и 2) некоторые имена errno имеют одинаковые номера в некоторых системах. - person mtraceur; 11.08.2019

изменить: части, не относящиеся к делу после исправления опечатки в вопросе.

Говоря о POSIX, как указано в заголовке, вы должны в значительной степени закончить с файлом заголовка errno.h, упомянутым в вашем вопросе.

Взгляните на стандарт, чтобы увидеть полный список макросов, которые должны быть там определены. (http://pubs.opengroup.org/onlinepubs/9699919799/)

Используя gcc, вы сможете получить список всех определений макросов в действии после включения errno.h, используя gcc -dM -E /usr/include/errno.h вместо того, чтобы вручную искать дерево включения, начинающееся с него.

Используя эвристику, более или менее все определения макросов, начинающиеся с заглавной буквы E, должны быть кодами ошибок, вы можете дополнительно сузить список с помощью grep, awk или другого инструмента по вашему выбору.

gcc -dM -E /usr/include/errno.h | awk '$2 ~ /^E/ {print $3 "\t" $2}' - это версия, с которой я экспериментировал, убирая эти строки.

Между тем, как написано в разделе комментариев, abligh придумал gcc -dM -E /usr/include/errno.h | egrep "^#define E" | cut -c 9- | sort -n -k 2, который также должен предоставить отсортированный список.

person mikyra    schedule 04.05.2015
comment
Это не я проголосовал против, но это была всего лишь опечатка. Его тоже нет в errno.h. Определения ошибок (во всяком случае в Linux) находятся в серии вложенных включаемых файлов, и поэтому их нелегко найти. - person abligh; 04.05.2015
comment
... более того, стандарт POSIX здесь мало пригоден, поскольку значение ошибок может различаться в разных реализациях (например, между Linux и OS-X). Именно поэтому я хочу вернуться к символической константе! - person abligh; 04.05.2015
comment
gcc -dM -E /usr/include/errno.h должен предоставить вам все макросы, определенные в errno.h, поскольку gcc выполнит поиск включаемых файлов за вас. Добавлю этот совет к ответу. - person mikyra; 04.05.2015
comment
интересный. Лучшее, что я могу сделать, это gcc -dM -E /usr/include/errno.h | egrep "^#define E" | cut -c 9- | sort -n -k 2, который, кажется, перечисляет их в основном по порядку. Не стесняйтесь включать это в свой ответ (или писать менее хакерски), и я бы поддержал. - person abligh; 04.05.2015

По крайней мере, в Ubuntu есть пакет с именем moreutils, который содержит программу с именем errno, написанную Ларсом Вирзениусом, он будет делать то, что вы хотите:

% errno 10 20 30 666
ECHILD 10 No child processes
ENOTDIR 20 Not a directory
EROFS 30 Read-only file system

Я тестировал эту программу на программе Python, и она, по крайней мере, отображает все ошибки, доступные в Python. Однако в моем Python всего 130 кодов; errno возвращает 134. Из 134 этих 3 дубликатов, поэтому обратное отображение не является уникальным. Тот, который отсутствовал в модуле Python errno, но был доступен в errno, был EHWPOISON 133 Memory page has hardware error.

person Antti Haapala    schedule 11.08.2019

Perl так популярен в прошлом сезоне, вот способ сделать это на Python, который в настоящее время более доступен! В нем также есть errno модуль, у которого есть обратная карта, называемая errno.errorcode.

>>> import errno
>>> errno.errorcode[10]
'ECHILD'

Из командной строки:

python -c 'import errno; print(errno.errorcode[10])'

Или поместить его в отдельный скрипт:

#!/usr/bin/python
import errno, sys

for i in sys.argv[1:]:
    code = int(i)
    print('{0:8d} - {1}'.format(code, errno.errorcode.get(code, '<unknown>')))

тогда errno.py 10 20 30 666 напечатает

      10 - ECHILD
      20 - ENOTDIR
      30 - EROFS
     666 - <unknown>
person Antti Haapala    schedule 11.08.2019

#ifndef NDEBUG
        fprintf(stderr, "Line %d: Error value: %d\n", __LINE__, errno);
#endif

Затем поищите напечатанное значение в вашем отладчике.

person Aioi Yuuko    schedule 04.05.2015
comment
Я думаю, что идея состоит в том, чтобы получить текстовое представление символа ошибки, чтобы вы могли распечатать его вместо (невзрачного) числового значения. - person M Oehm; 04.05.2015
comment
Это печатает целочисленное значение ошибки (например, 10), а не символическое представление (например, ECHILD). - person abligh; 04.05.2015