如何在 C 中打印 errno 的符号名称?
Posted
技术标签:
【中文标题】如何在 C 中打印 errno 的符号名称?【英文标题】:How can I print the symbolic name of an errno in C? 【发布时间】:2013-11-22 00:22:24 【问题描述】:我可以使用perror()
或strerror()
打印属于errno
的“人类可读”错误消息,但是如果我也想要打印符号名称(例如, errno
的“EAGAIN
”)?
有什么方便的函数或宏来做到这一点?
更新:根据下面接受的答案及其 cmets 的想法,附上我最终编写的代码:
#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(\\$0, /^#[[: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 '\0' 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++] = '\0';
if (pclose(f) == -1)
perror("Failed to pclose() in get_errno_name()");
return -1;
return read_size;
【问题讨论】:
有趣的代码。我不会在生产环境中部署一个运行 C 编译器的函数——它既慢又“不可靠”,因为有些人在运行时没有编译器。假设错误消息集通常不会更改,除非(可能)在操作系统升级时发生变化,因此有足够的机会缓存结果,即使这样,向后兼容性也意味着大多数错误编号保持不变。不过,您可以使用您的代码收集所有系统错误的数据,然后在编译时从数据驱动的函数中使用该输出。 @JonathanLeffler 感谢您的反馈。同意两个帐户。我可能应该提到,以上内容绝对不能这样部署(除非您不介意运行时对 gcc 和 gawk 的依赖......)。是的;像这样的代码最好在编译时作为 (c)make 脚本的一部分运行。不过,我的项目往往很小,所以我通常不会理会这样的脚本;这就是为什么上面的代码最适合我的个人调试版本。 【参考方案1】:我最近写了the errnoname
library,它有一个errnoname
函数可以让你这样做。
不幸的是,仍然没有标准的 API 可以做到这一点。
Mine 的目标是成为您可以在任何系统上便携使用的东西,同时仍能覆盖该系统上的所有 errno
名称。到目前为止,包括 Linux、Darwin(macOS、ios 等)、FreeBSD、NetBSD、OpenBSD、DragonflyBSD、几个闭源 Unix、Windows 和其他一些。
正如其他答案所示,唯一的“困难”部分是获取 errno
名称和值的列表以进行查找,知道哪些 errno
甚至在目标系统上定义,并详尽处理所有情况多个errno
名称可能映射到同一个数字。
所以在errnoname
库中,您不必处理任何这些。我将许多操作系统的errno
名称收集到一个列表中作为一个单独的步骤,然后从中生成实际发布的 C 代码。 C 代码对每个名称使用#ifdef
,因此它可以在任何系统上编译,而不管系统具有哪个errno
名称和值。编译后的结果只是简单高效的代码,无需调用任何程序或在库头中搜索errno
。
无论如何,由于它是在“零条款 BSD 许可”(0BSD) 下发布的,这是一种许可许可,或者更准确地说是等效于公共领域的许可,您可以使用它为所欲为。
下面是我库中函数的旧复制粘贴,因此即使我的 repo 链接失效,这个答案也很有用。几点说明:
此处的副本仅涵盖我能找到的所有 errno
名称截至 2019 年 8 月开始 - 从那时起我找到了其他人。
如果你给它一个不知道名字的errno
值,它会返回一个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;
【讨论】:
【参考方案2】:没有一个简单的方法可以做到这一点。
您可以创建一个程序——我已经创建了一个程序,它可以重新打包为库函数——将数字转换为名称。但是生成表格比较困难。我使用 Perl 脚本运行带有选项 (-H
) 的编译器(GCC 或等效项)来列出包含 /usr/include/errno.h
的头文件,然后扫描这些文件,查找名称(#define
加上 @987654324 @ 后跟一个大写字母或数字)、数字和 cmets。这适用于 Linux、Mac OS X、Solaris、HP-UX、AIX。这并不是特别琐碎。
请注意,Mac OS X 上的 errno.h
包含一个名称 ELAST
(保留供实现使用的名称),它是最大数字的副本(但映射因版本而异;它是 105在山狮,我相信,但在小牛队是 106)。
【讨论】:
echo '#include <errno.h>' | $CC -dM -E - | grep -E '^#[[:space:]]*define[[:space:]]+E'
@R..:或多或少,是的,但如果你要编译它,你必须将符号名称转换(副本)为字符串,并可能捕获评论(尽管您可以使用strerror()
来处理错误消息部分)等
这只是一个脚本,以一种干净的、大部分可移植的方式获取#define
s 的列表(比 grepping 会严重破坏交叉编译和其他设置的特定路径名更好)。您仍然需要将输出处理成字符串表。
我们可以对可移植性提出质疑(-dM
和 -
可以与 gcc
一起使用,-H
也可以,并且可能与 clang
和 icc
一起使用,但不是必然是其他编译器)。输出略有不同,但最终结果大致相同。我认为我们实际上非常同意。 Perl 读取标题的一个优点是它不必关注#ifdef
ery 并且可以拾取您提供的内容可能遗漏的定义。不是很清楚。某些平台可能会重新组织信息的布局并搞砸一切。不管怎样,它或多或少都有问题。
在完美的世界中,系统将它们与人类可读的字符串打包不是更容易吗?例如“错误的文件描述符 (EBADF)”。毕竟它们已经被映射了。【参考方案3】:
glibc 为此提供了一个函数(一个 GNU 扩展):strerrorname_np()
。
在<string.h>
中声明。
对于有效值返回 errno
名称,对于无效值返回 NULL
。
man strerrorname_np
它是在 glibc 2.32 中添加的。
【讨论】:
【参考方案4】:据我所知,你不能。无论如何,一些整数错误常量映射到多个符号名称,例如EAGAIN 和 EWOULDBLOCK。显然,您可以在设置 errno 的命令的手册页上查找它们。
【讨论】:
EAGAIN 和 EWOULDBLOCK 是仅有的两个可能相同。所有其他人必须具有不同的值。 Linux 上也有EDEADLK 和EDEADLOCK POSIX<errno.h>
将 EAGAIN 和 EWOULDBLOCK 列为一对,但也列出了 ENOTSUP 和 EOPNOTSUPP。平台可能有其他重复名称。由于给定号码只需要一个名称,因此您可以选择一个作为规范名称。
@Duck EDEADLK 和 DEADLOCK 的意思是一样的……(DEADLK 是 DEADLOCK 的缩写形式)【参考方案5】:
如果你知道你期待什么错误,你可以写大块 switch/case
或 if/else
反对 errno
,采用以下风格:
if (errno == EAGAIN)
fprintf(stderr, "EAGAIN");
这样做的明显问题是,如果您想要特定的 errno 'name',则需要针对每个可能的选项进行编写,而且有很多。
【讨论】:
这不是很笼统。至少创建一个使用字符串数组的函数,并返回一个char const *
给数字对应的名字。【参考方案6】:
我不知道有什么函数可以做到这一点,但如果您熟悉程序中返回的错误,编写一个函数并不难。
您可以编写包含 strerror() 输出的字符串,并使用 for 循环和带有 strcmp() 的 if 语句(根据成功或失败返回一个值)来比较您编写的字符串。如果它们相同,则可以将符号名称*设置为另一个字符串。
【讨论】:
为什么你需要strcmp
反对strerror
的输出?
你可以在 errno.h 中查找它们并在此基础上编写一些东西。这会起作用......直到它没有因为某些事情发生变化。【参考方案7】:
由于符号名称存储为枚举,C
将它们视为Ints
。您将必须创建一个类似于此 SO 问题 How to convert enum names to string in c 的函数。您可能很容易将其缩短为宏,但必须为每个错误创建一个案例。
【讨论】:
C 标准(至少是 C99)规定E*
常量是宏,而不是枚举。
好吧,GNU 编译器打开它们并将它们视为枚举。对于误导性信息,我深表歉意。以上是关于如何在 C 中打印 errno 的符号名称?的主要内容,如果未能解决你的问题,请参考以下文章