首页 文章

如何检查errno的值?

提问于
浏览
4

我正在使用系统调用,如果失败,我需要为不同的errnos做不同的事情 .

我需要编写看起来像这样的代码:

int res;
res = systemCall();
if (res == -1)
{
    if (errno == ENOMSG)
    {
        doSomething();
    }
    else
    {
        doSomethingElse();
    }
}

perror没有帮助,因为它只打印值 .

至于strerro - 如果它是我需要的,我不是如何使用它,因为here它说实际字符串与错误不同 . 从手册页引用:"(For example, if errnum is EINVAL, the returned description will be "无效参数")" .

我正在使用Linux . 系统调用:msgsend和msgrcv(https://linux.die.net/man/2/msgrcv) . 我不确定你问的C库是什么 .

我看到我没有很好地解释自己 .

语句if(errno == ENOMSG)是否有效?是否有这样的变量errno?基本上我的问题是:为了测试errno,应该在 if 语句中进行什么?

3 回答

  • 9

    我假设您使用的是Linux,我认为您不直接使用系统调用,而是在syscalls(2)中列出的一些(简单)包装器(来自您的C库) . 请注意,一些奇怪的系统调用不是由C库包装的(一个众所周知的解包系统调用示例是sigreturn(2),您可能永远不应该使用它) . C库通常是GNU glibc,但它可能是musl-libc等 . 另请注意,内核原始系统调用与普通C函数具有不同的calling conventions(因此实际上需要libc包装器,并且负责处理 errno ) . 另请注意,errno(3)通常是一个宏(几乎表现为某个变量) .

    msgrcv(2)手册页文档 errno 可以是 E2BIGEACCESEFAULT ... ENOMSGENOSYS ...之一(请参阅该手册页以获取所有可能错误的列表) .

    所以你会编写类似的东西

    ssize_t siz = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
    if (siz<0) { // msgrcv failed and has set errno
      if (errno == ENOMSG) 
        dosomething();
      else if (errno == EAGAIN) 
        dosomethingelse();
      /// etc
      else {  
         syslog(LOG_DAEMON|LOG_ERR, "msgrcv failure with %s\n",
                strerror(errno)); 
         exit(EXIT_FAILURE); 
      };
    };
    

    语句if(errno == ENOMSG)....是否有效?

    是的;您希望仅在某些系统调用失败后测试 errno (例如,当 siz<0 时) .

    有这样的变量errno吗?

    不再 . 请仔细阅读errno(3)文档 . 你不应该声明 extern int errno; (这在20世纪80年代是可能的,而不是在21世纪)但是你应该总是 #include <errno.h> 并使用 errno 好像它是一个变量,但它几乎总是一些宏(其定义出现在 /usr/include/bits/errno.h 中,包括在 /usr/include/errno.h ) .

    顺便说一句,SysV式设施往往过时,并不总是可用 . 我建议使用POSIX消息队列工具,阅读mq_overview(7) .

    您可能想要阅读免费下载的Advanced Linux Programming(一本旧书;您可以购买更好更新的东西)和/或从intro(2)syscalls(2)intro(3)可以访问的所有手册页 .

  • 3

    如何检查 errno 的值:

    • 你需要 #include <errno.h> .

    • 是的,你绝对可以说 if(errno == ENOENT) { ... } 之类的东西,这是常见的推荐方式 .

    • 通常,请勿使用 errno 来确定是否发生了错误 . 检查函数的返回值,如果返回值指示错误,则检查 errno 以查看错误是什么 . (下面有更多内容 . )

    • errno 看起来像一个变量,但只要你只是说 if(errno == ENOENT) { ... } 之类的话,它实际上并不是你所关心的 . 但你可能不应该尝试做像 int errno_ptr = &errno; 这样的事情 .

    • 您可以使用 perror()strerror() 等函数来获取与 errno 值对应的人类可读错误字符串 . 但是,是的,你得到的字符串通常是"No such file or directory" . 我知道没有好办法将errno值 ENOENT 转换为字符串 "ENOENT" .

    更多地谈论#3 . 有时候说出类似的东西很诱人

    errno = 0;
    printf("Hello, world!\n");
    if(errno != 0) {
        fprintf(stderr, "printf failed!\n");
    }
    

    但是不要这样做 . 相反

    errno = 0;
    int retval = printf("Hello, world!\n");
    if(retval < 0) {
        fprintf(stderr, "printf failed!\n");
    }
    

    原因是,在完成其工作的某个地方, printf 可能已经做了导致错误的事情,设置了 errno ,但 printf 可能已从该错误中恢复并继续成功完成 .

    如果没有错误(我认为一个例子可能是 atoi ),有一些库函数可以保证不会触及errno,但总的来说,这是你必须要小心的 .

    更多地谈论#4 . errno 看起来像一个变量,更具体地说,它看起来像一个全局变量 . 但当然全局变量都很糟糕 . 但是 errno 已经永远存在;有数以千万计的代码行使用它;它__649736_太迟了"fix"它 . 所以与其,如果你偷看幕后,你会发现大多数实现都是这样的

    extern int __errno_pointer;
    #define errno (*__errno_pointer)
    

    要么

    extern int *__errno_pointer_function();
    #define errno (*__errno_function())
    

    通过这种方式,即使在多线程代码中,他们也可以安排 errno 合理地正常工作 .

  • 8

    包括errno.h

    一些例子:

    // Error codes
    #define EPERM        1  /* Operation not permitted */
    #define ENOENT       2  /* No such file or directory */
    #define ESRCH        3  /* No such process */
    #define EINTR        4  /* Interrupted system call */
    #define EIO          5  /* I/O error */
    #define ENXIO        6  /* No such device or address */
    #define E2BIG        7  /* Argument list too long */
    #define ENOEXEC      8  /* Exec format error */
    #define EBADF        9  /* Bad file number */
    #define ECHILD      10  /* No child processes */
    #define EAGAIN      11  /* Try again */
    #define ENOMEM      12  /* Out of memory */
    #define EACCES      13  /* Permission denied */
    #define EFAULT      14  /* Bad address */
    #define ENOTBLK     15  /* Block device required */
    #define EBUSY       16  /* Device or resource busy */
    #define EEXIST      17  /* File exists */
    #define EXDEV       18  /* Cross-device link */
    #define ENODEV      19  /* No such device */
    #define ENOTDIR     20  /* Not a directory */
    #define EISDIR      21  /* Is a directory */
    #define EINVAL      22  /* Invalid argument */
    #define ENFILE      23  /* File table overflow */
    #define EMFILE      24  /* Too many open files */
    #define ENOTTY      25  /* Not a typewriter */
    #define ETXTBSY     26  /* Text file busy */
    #define EFBIG       27  /* File too large */
    #define ENOSPC      28  /* No space left on device */
    #define ESPIPE      29  /* Illegal seek */
    #define EROFS       30  /* Read-only file system */
    #define EMLINK      31  /* Too many links */
    #define EPIPE       32  /* Broken pipe */
    #define EDOM        33  /* Math argument out of domain of func */
    #define ERANGE      34  /* Math result not representable */
    

    您的实现可能包含更多错误,例如 /usr/include/asm-generic/errno.h .

相关问题