如何将UNIX中的errno转换为相应的字符串?

a64a0gku  于 2023-03-29  发布在  Unix
关注(0)|答案(6)|浏览(188)

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

gcuhipw9

gcuhipw91#

应该可以。
FYI,这样你就可以更容易地找到这些东西,你自己:如果你输入man errno(或者你正在研究的任何函数),并查看手册页的最底部,你会看到一个相关函数的列表。如果你man其中的每一个(根据它们的名字猜测先做哪个),你通常会找到类似问题的答案。

scyqe7ek

scyqe7ek2#

这是另一个解决方案,它完全解决了你的问题,但用Python而不是C:

>>> import errno
>>> errno.errorcode[errno.EIDRM]
'EIDRM'
zpjtge22

zpjtge223#

现在有一个errno实用程序随moreutils包分发。

$ 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
fkvaft9z

fkvaft9z4#

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

mbzjlibv

mbzjlibv5#

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

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

打印出一个漂亮的“...\n89 EIDM\n...”表,您可以将其进一步转换为您想要使用此函数的编程语言的数据结构。

rbl8hiat

rbl8hiat6#

我最近写了errnoname来做这件事。
在UNIX中没有标准的函数来实现这一点(GNU的glibc有strerrorname_np,但目前没有其他C库提供它,所以它甚至不能在所有Linux发行版上使用,更不用说其他任何地方了。
strerror(也称为strerror_rstrerror_lperror)打印一个“人性化”的提示,提示错误是什么,但是它们的输出是

  • 通常没有记录,
  • 不标准化,
  • 不保证遵循对长度或格式的任何约束,
  • 通常因区域设置而异,以及
  • 并不总是在所有情况下都有意义(例如,他们倾向于为EEXIST打印File exists,即使该错误经常返回不是文件的东西)。

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

  • 其他代码不能可靠地解析它们(对于自动化、监视、脚本、 Package 程序等更糟),
  • 会在边缘情况下误导,并且
  • 妨碍有经验的技术用户。

具有讽刺意味的是,没有任何东西 * 阻止 * 这些函数在任何情况下都使用errno符号名作为它们的错误字符串-这将在标准的字母范围内,特别是如果它们只针对特定的区域设置这样做,比如特殊的C区域设置。
无论如何,由于我的errnoname是在“零条款BSD许可证”(0 BSD)下发布的,这是一个许可证,或者更准确地说,是一个公共域等效许可证,您可以用它做任何您想做的事情。
为了使这个答案独立,同时仍然符合答案字符限制,下面是errnoname函数的两个缩写变体。
errnoname中,它们都实现了,但在这里我将它们的要点分离出来,使它们更具可读性。
几个注意事项:
1.这涵盖了Linux,达尔文(Mac OS X和iOS X),FreeBSD,NetBSD,OpenBSD,DragonflyBSD和几个闭源Unix的所有或大部分errno名称,截至2020年1月。
1.如果你给予它一个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;
}

变体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;
}

相关问题