【问题标题】:Convert POSIX integer errno to compile-time constant将 POSIX 整数 errno 转换为编译时常量
【发布时间】:2015-05-04 20:26:54
【问题描述】:

偶尔(例如使用strace、gdb 等)发现一个POSIX 调用将errno 设置为一个整数值,并且想知道编译时间C 常量(更准确的预处理器定义)来检查对于它(例如ECHILD) - 参见例如waitpid for child process not succeeding.

EG 在上述链接问题中,整数错误号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 开头的具有适当值的常量。

【问题讨论】:

  • 问题有点不清楚。你的意思是给定 ECHILD 的 int 值,你想要那个符号“ECHILD”的 /name/?
  • @BadZen - 准确地说。我会澄清的。
  • @cdarke - 我认为这与我提到的第二个类似 - 我不需要 在 C 中这样做。

标签: c posix errno


【解决方案1】:

您可以直接调用 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

有几点需要注意:

  • 这几乎肯定不是万无一失的。这很可能会遗漏一些事情,并弄错其他事情。一方面,如果有其他宏定义,在any文件#include-ed(直接或间接)由errno.h,那么grep '^#define E'可能不足以过滤掉cpp 命令的输出中所需的 errno 定义。这绝不是这种方法可能失败的唯一方式。
  • 显然,在某些情况下,例如#define EWOULDBLOCK EAGAIN,其中一个Exxxx 值被定义为另一个先前定义的值的同义词。
  • 序列中似乎有一些缺失值,例如 41。我不确定这是否正常,或者这是否是这种方法缺失的示例。

排除这些免责声明后,应该可以使用这种方法作为脚本的基础(然后您可以选择从您的 Makefile 中调用该脚本)来自动生成查找表(例如,errno-lookup.c)并在您的代码中引用此表以获取任何给定 errno 值的关联符号。

【讨论】:

    【解决方案2】:

    &lt;errno.h&gt; 中定义(直接或间接)的EFOO 常量集及其值因系统而异。而且经常会有不止一个EFOO常量;例如,在我的系统上,EAGAIN 和 EWOULDBLOCK 的值都为 11。因此,对于给定的数字 errno 值,不一定有唯一的 EFOO 符号。

    我收集了来自各种系统的 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
    

    【讨论】:

      【解决方案3】:

      我最近写了 the errnoname library ,它有一个 errnoname 函数可以做到这一点。

      因此,您可以从问题#include "errnoname.h" 中获取示例程序,只需将strerror 替换为errnoname,然后将其编译/链接为errnoname.c。

      正如其他答案所表明的那样,errnoname 函数本身没有什么难或复杂的,手动实现真的很乏味,以确保包含所有 errno 名称,以及所有的小角落-处理案件。

      例子:

      • 正如另一个答案指出的那样,有一些对,例如 EWOULDBLOCK 等于 EAGAIN,在某些系统上具有相同的值,在其他系统上具有不同的值,并且
      • errno 名称根本不能保证是连续(因此我建议将其作为 switch 语句而不是数组来实现,因为在一些罕见或未来的系统上,它可能是一个非常非常效率低下的大型数组,其中包含许多未使用的条目(如果它甚至可以编译)。

      无论如何,由于它是在“零条款 BSD 许可”(0BSD) 下发布的,这是一种许可许可,或者更准确地说是等效于公共领域的许可,您可以使用它为所欲为。

      下面是从我的库中直接复制粘贴的函数,因此这个答案可以独立存在。几点说明:

      1. 这涵盖了截至 2019 年 8 月开始时我可以找到的用于 Linux、Darwin(Mac OS X 和 iOS X)、FreeBSD、NetBSD、OpenBSD、DragonflyBSD 和几个闭源 Unix 的所有 errno 名称.

      2. 如果你给它一个不知道名字的errno值,它会返回一个NULL指针。

      #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;
      }
      

      【讨论】:

        【解决方案4】:

        这是我自己的答案,基于其他人加上一些 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
        

        我相信它会通过一些错误处理得到改进。

        【讨论】:

          【解决方案5】:

          这是一个似乎可以做到这一点的 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;
          }
          

          【讨论】:

          • 这个怎么用?它给了我:Not a GLOB reference at ./e.pl line 10.(Ubuntu 14.04,perl v5.18.2)
          • 显然这里的某些东西与我使用的旧 perl 版本不同,哎呀。
          • 针对 perl 5.20 更新。
          • 我更新了你的答案,所以当${$ns-&gt;{$_}} 是undef 时,它不再打印单元化警告。现在效果很好!
          • 另请注意,这是迄今为止唯一不需要解析包含文件(可能不可靠)或构建自己的表的答案。
          【解决方案6】:

          strerror() 函数通常(总是?)在返回的消息中的某处提供该常量的名称。这是一个 hack,但你可以为第一组以“E”开头的连续大写字母...

          【讨论】:

          • 实际上,测试这表明我的“通常/总是”非常乐观。 =/
          • 尽管它们或多或少是标准的,所以也许只是一个带有大量 case EPERM: { return "EPERM"; } 等的巨型开关实现是要走的路。
          • 我从来不知道它会这样做。我提到的情况并非如此(见问题)。
          • 是的,看起来它不适合它们中的任何一个 - 这让我觉得我记得 strerror() 的另一个函数......
          【解决方案7】:

          您可以使用符号本身来编写错误符号表。显然,这要求您包含定义要考虑的常量的所有标题。

          常量列表是从man page of 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;
          }
          

          【讨论】:

          • 您应该知道将其设为数组存在风险:1) 无法保证 errno 值是连续的,甚至是相当小的,2) 某些 errno 名称在某些系统上具有相同的数字。
          【解决方案8】:

          编辑:在问题中的错字被修复后不相关的部分已被删除。

          如标题中所述谈论 POSIX,您应该已经完成​​了问题中提到的 errno.h 头文件。

          查看标准以查看应在该标准中定义的完整宏列表。 (http://pubs.opengroup.org/onlinepubs/9699919799/)

          使用 gcc,您应该能够在使用 gcc -dM -E /usr/include/errno.h 包含 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,它也应该提供已排序的列表。

          【讨论】:

          • 投反对票的不是我,但这只是一个错字。它也不在errno.h 中。错误定义(无论如何在 Linux 中)位于一系列嵌套的包含文件中,因此不容易找到。
          • ...此外,POSIX 标准在这里用处不大,因为错误的 value 可能因实现而异(例如,在 Linux 和 OS-X 之间)。这正是我想回到符号常数的原因!
          • gcc -dM -E /usr/include/errno.h 应该为您提供errno.h 中定义的 all 宏,因为 gcc 将为您进行包含文件搜索。我会将此建议添加到答案中。
          • 有趣。我能做的最好的事情是gcc -dM -E /usr/include/errno.h | egrep "^#define E" | cut -c 9- | sort -n -k 2,它似乎主要按顺序列出它们。随意将其包含在您的答案中(或者写得不那么生硬),我会投赞成票。
          【解决方案9】:

          至少在 Ubuntu 上有一个名为 moreutils 的软件包,其中包含由 Lars Wirzenius 编写的名为 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。

          【讨论】:

            【解决方案10】:

            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>
            

            【讨论】:

              【解决方案11】:
              #ifndef NDEBUG
                      fprintf(stderr, "Line %d: Error value: %d\n", __LINE__, errno);
              #endif
              

              然后在调试器中查找打印的值。

              【讨论】:

              • 我认为这个想法是获取错误符号的文本表示,以便您可以打印它而不是(无法描述的)数值。
              • 打印错误的整数值(例如 10),而不是符号表示(例如 ECHILD)。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-10-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-11-26
              • 1970-01-01
              • 2015-01-22
              相关资源
              最近更新 更多