如何检查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
可能是E2BIG
, EACCES
, EFAULT
… ENOMSG
, 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
)。
有这样一个变量
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
的值:
- 您需要
#include
。 - 是的,你可以肯定地说
if(errno == ENOENT) { ... }
,这是常见和推荐的做法。 - 通常,不要使用
errno
来确定发生了错误。 检查函数的返回值,如果返回值指示错误,则检查errno
以查看错误是什么。 (以下更多内容。) -
errno
看起来像一个变量,但实际上并非如此。 只要您说if(errno == ENOENT) { ... }
类的内容,这与您无关。 但你可能不应该尝试做一些像int errno_ptr = &errno;
。 - 您可以使用
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
。