如何检查errno的值?

时间:2017-09-02 11:44:21

标签: c system-calls errno

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

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

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

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

至于strerro - 如果它是我需要的,我不是如何使用它,因为here它表示实际字符串与错误不同。从手册页引用:"(例如,如果errnum是EINVAL,则返回的描述将是"无效的参数")"。

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

我发现自己并没有很好地解释自己。

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

3 个答案:

答案 0 :(得分:9)

如何检查errno

的值
  1. 您需要#include <errno.h>
  2. 是的,您可以肯定地说if(errno == ENOENT) { ... }之类的内容,这是常见的推荐方式。
  3. 通常,使用errno来确定是否发生了错误。检查函数的返回值,如果返回值指示错误,则检查errno以查看错误是什么。 (更多内容见下文。)
  4. errno看起来像一个变量,但它实际上并非如此。只要您说if(errno == ENOENT) { ... }之类的内容,这并不会引起您的注意。但你可能不应该尝试做int errno_ptr = &errno;
  5. 之类的事情
  6. 您可以使用perror()strerror()等函数来获取与errno值对应的人类可读错误字符串。但是,是的,你得到的字符串通常是&#34;没有这样的文件或目录&#34;。我知道将errno值ENOENT转换为字符串"ENOENT"没有好办法。
  7. 多说一点#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永远存在;有数以千万计的代码行使用它;它基本上还很方便;它已经来不及修复&#34;它。所以,相反,如果你躲在幕后,你会发现大多数实现都是这样的

    extern int __errno_pointer;
    #define errno (*__errno_pointer)
    

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

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

答案 1 :(得分:8)

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

errno(3)手册页文档errno可以是E2BIGEACCESEFAULT ... ENOMSG,{{{ 1}} ...(请参阅该手册页以获取所有可能错误的列表)。

所以你会编写类​​似

的代码
ENOSYS
  

声明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

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

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

您可能希望阅读可免费下载的mq_overview(7)(一本旧书;您可以购买更好更新的内容)和/或可以从Advanced Linux Programming获得的所有手册页&amp; intro(2)&amp; syscalls(2)

答案 2 :(得分:3)

包括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