在 UNIX 中是否有将 errno 转换为相应字符串的函数,例如将 EIDRM 转换为 "EIDRM"。使用整数 errnos 进行错误调试非常烦人。
UNIX中有一个函数 strerror()可以将errno转化为对应的字符串形式。例如,strerror(EIDRM)将返回"EIDRM"。strerror()
应该就可以了。 http://linux.die.net/man/3/strerror
请注意,为了便于查找这些内容,您可以自己找到:如果您键入 man errno(或其他要调查的函数),并查看手册页面的底部,您将看到相关函数列表。如果您依次使用 man
查看它们(根据名称猜测哪些先进行),通常可以找到类似问题的答案。
这里有另一种解决方案,完全解决了你所遇到的问题,但它是用 Python 而不是 C 实现的:
>>> import errno
>>> errno.errorcode[errno.EIDRM]
'EIDRM'
errno
值的子集,因此在某些系统上,它不会为所有值都有条目。对于典型情况,这不是问题,但如果您将其用作通用查找错误代码的方式,则可能会遇到此问题。 - mtraceur现在已经有一个由moreutils包分发的errno
工具。
$ errno -h
Usage: errno [-lsS] [--list] [--search] [--search-all-locales] [keyword]
$ errno -l
EPERM 1 Operation not permitted
ENOENT 2 No such file or directory
ESRCH 3 No such process
EINTR 4 Interrupted system call
EIO 5 Input/output error
ENXIO 6 No such device or address
E2BIG 7 Argument list too long
ENOEXEC 8 Exec format error
...
$ errno 11
EAGAIN 11 Resource temporarily unavailable
$ errno -s Ouput
EIO 5 Input/output error
我不确定这种enum
类型的名称,但是为了调试和错误报告目的,您可以使用C函数perror(3)
或strerror(3)
,它们返回错误代码的可读表示。有关更多详细信息,请参阅man页面。
perror
是一个用于调试与 errno
相关问题的工具,并将其消息写入 STDERR
。 - Andrey Vlasovskikh
man errno|egrep ' [0-9]+ E[A-Z]+'|sed 's/^ *//'|cut -d' ' -f1,2
这段代码会打印出一个漂亮的表格,其中包含“...\n89 EIDM\n...”等信息。您可以将其转换为所需编程语言的数据结构。
我最近写了errnoname
来实现这个功能。
在UNIX中没有标准函数可以实现这个功能。(GNU的glibc有strerrorname_np
,但是其他C库目前都没有提供它,因此它甚至不在所有Linux发行版上都可用,更别说其他地方了。)
strerror
(还有strerror_r
、strerror_l
、perror
)打印出关于错误的“人性化”提示,但它们的输出:
EEXIST
打印文件已存在
,即使该错误经常返回给非文件的事物)。这意味着它们表面上很用户友好,但实际上并不是。
具有讽刺意味的是,没有什么阻止这些函数在所有情况下都使用 errno
符号名称作为其错误字符串 - 特别是如果它们只针对特定语言环境执行此操作,例如特殊的C
语言环境。但我所知道的libc都没有这样做。
无论如何,由于我的 errnoname
已在“零条款BSD许可证”(0BSD)下发布,这是一种宽松的许可证,或者更准确地说是等同于公共领域的许可证,所以您可以随心所欲地使用它。
为了使这个答案独立存在,同时仍然符合答案字符限制,在下面提供了 errnoname
函数的两个缩写版本。
请注意:
这涵盖了截至2020年1月初的Linux、Darwin(Mac OS X和iOS X)、FreeBSD、NetBSD、OpenBSD、DragonflyBSD以及几个闭源Unix的所有或大部分errno
名称。
如果您提供一个它不知道名称的errno
值,它将返回空指针。
这个非常便携且简单,没有需要担心的边缘情况。它可以编译成几乎任何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;
}
这个方法更加明显高效,并且会非常可靠地编译出高效的代码,因为它使数组查找变得明确,不依赖于编译器的优化。
只要系统具有正数、相对较小和相当连续的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;
}
ERRNONAME_SAFE_TO_USE_ARRAY
激活)到errnoname中。(在优化部分有文档记录。)感谢您提出这个问题。在重新考虑如何解决它之前,我一直在等待是否有对基于数组的方法的需求。 - mtraceurcase 0: return 0
并没有改变结果 - 所以我猜测优化器正在根据已经识别出零情况与任何其他越界情况相同的逻辑的抽象形式做出决策,并且这种逻辑排除了启发式地注意到一个额外的数组条目可能比一个始终执行的指令更有效率的可能性。 - mtraceursub
然后 cmp
而不仅仅是 cmp
。 - mtraceur
strerror()
的字符串是本地化的。当我检查一个错误字符串时,发现我的用户平台返回的是“Arquivo ou diretório não encontrado”,而不是“没有这样的文件或目录”。(这是在一个errno值本身没有暴露的语言中。) - David Givenrm
、mv
和iproute2命令这样的工具,它们都缺乏其他区分例如实际上意味着幂等成功的错误和其他错误的方法。现在我们只需要说服每个人将errno
名称以可解析的方式放入他们的错误消息中。 - mtraceur