我假设你正在使用Linux,并且我认为你并没有“直接”使用系统调用,而是使用了一些(简单的)包装器(从你的C库中列出),这些包装器在syscalls(2)中列出。请注意,一些奇怪的系统调用未被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) {
if (errno == ENOMSG)
dosomething();
else if (errno == EAGAIN)
dosomethingelse();
else {
syslog(LOG_DAEMON|LOG_ERR, "msgrcv failure with %s\n",
strerror(errno));
exit(EXIT_FAILURE);
};
};
语句if (errno == ENOMSG)
是有效的吗?
是的,当某些系统调用失败时(例如siz<0
),您希望仅在测试errno
后。
是否有名为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)可达到的所有手册页面。
errno
设置为零,并且除非函数指示错误并记录设置errno
,否则不应该对其进行测试。请注意,许多 pthreads 函数不设置errno
;例如,它们返回错误号。此外,即使成功,函数也可以将errno
设置为非零值。例如,在 Solaris 上,如果标准输出不是终端,则即使printf()
调用成功,也可能将errno
设置为 ENOTTY。 - Jonathan Leffler