42

UNIX 中是否有任何函数可以将 errno 转换为相应的字符串,例如 EIDRM 到“EIDRM”。调试这些整数错误来检查错误非常烦人。

4

6 回答 6

73

strerror()应该这样做。 http://linux.die.net/man/3/strerror

仅供参考,这样您自己就可以更轻松地找到这些东西:如果您输入 man errno (或您正在研究的任何功能),并查看手册页的最底部,您将看到相关功能的列表。如果你们man每个人(根据他们的名字猜测首先要做什么),您通常会找到类似问题的答案。

于 2009-10-10T02:45:55.633 回答
13

只是另一种解决方案,可以完全解决您遇到的问题,但使用 Python 而不是 C:

>>> import errno
>>> errno.errorcode[errno.EIDRM]
'EIDRM'
于 2009-10-10T02:58:15.453 回答
8

现在有一个errnomoreutils包一起分发的实用程序。

$ 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
于 2012-12-25T01:10:16.783 回答
4

我不确定这种enum风格的名称,但出于调试和错误报告的目的,您可以使用返回错误代码的人类可读表示的 C 函数perror(3)strerror(3)有关详细信息,请参阅手册页。

于 2009-10-10T02:50:23.567 回答
3

如果您确实想要 EIDRM 而不是它的错误字符串:否。然而,在 OpenBSD 上,

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

打印出一张漂亮的“...\n89 EIDM\n...”表格,您可以将其进一步转换为您希望使用此功能的编程语言的数据结构。

于 2009-10-10T03:00:36.207 回答
2

在 UNIX 中没有执行此操作的标准函数。

但我最近编写了一个errnoname,它有一个errnoname功能正是这样做的。

strerror(也strerror_r, strerror_l, perror)打印关于错误是什么的“人类友好”提示,但它们的输出是

  • 通常无证,
  • 不规范,
  • 不保证遵循长度或格式的任何限制,
  • 通常根据区域设置而有所不同,并且
  • 并不总是在所有情况下都有意义(例如,它们倾向于打印File existsfor EEXIST,即使该错误通常针对非文件返回)。

这意味着它们表面上是用户友好的,但

  • 其他代码无法可靠地解析它们(对于自动化、监控、脚本、包装程序等来说更糟),
  • 在极端情况下可能会误导,并且
  • 妨碍技术经验丰富的用户。

具有讽刺意味的是,没有什么能阻止这些函数在所有情况下仅使用errno符号名称作为它们的错误字符串——它会在标准的字母范围内,特别是如果它们只针对特定的语言环境,比如特殊的C语言环境。但是我所知道的没有 libc 可以做到这一点。

无论如何,由于 myerrnoname是在“零条款 BSD 许可证”(0BSD)下发布的,这是一个许可许可证,或者更准确地说是一个等效于公共领域的许可证,你可以用它做任何你想做的事情。

为了使这个答案独立,同时仍然符合答案字符限制,下面是该errnoname函数的两个缩写变体。

它们都被实现了,但在errnoname这里我已经分离出每个的要点以使它们更具可读性。

几点注意事项:

  1. errno截至 2020 年 1 月,这涵盖了 Linux、Darwin(Mac OS X 和 iOS X)、FreeBSD、NetBSD、OpenBSD、DragonflyBSD 和几个闭源 Unix 的全部或大部分名称。

  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;
}
于 2019-08-11T07:01:09.640 回答