如何检查errno的值?

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

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

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

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

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

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

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

语句if(errno == ENOMSG)是否有效? 有这样一个变量errno? 基本上我的问题是:为了测试errno, if语句应该怎么做?

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

msgrcv(2)手册页记录了errno可能是E2BIGEACCESEFAULTENOMSGENOSYS ……(请参阅该手册页以获取所有可能错误的列表)。

所以你会编写类​​似的代码

 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就像它是一个变量,但它几乎总是一些宏(其定义出现在/usr/include/bits/errno.h ,包含在/usr/include/errno.h )。

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

您可能希望阅读可免费下载的高级Linux编程 (一本旧书;您可以购买更好更新的东西)和/或从介绍(2)和系统调用(2)和介绍(3)可以访问的所有手册页。

如何检查errno的值:

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

 extern int __errno_pointer; #define errno (*__errno_pointer) 

要么

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

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

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