我正在使用系统调用,如果失败,我需要为不同的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
语句中添加什么内容?
答案 0 :(得分:9)
如何检查errno
:
#include <errno.h>
。if(errno == ENOENT) { ... }
之类的内容,这是常见的推荐方式。errno
来确定是否发生了错误。检查函数的返回值,如果返回值指示错误,则检查errno
以查看错误是什么。 (更多内容见下文。)errno
看起来像一个变量,但它实际上并非如此。只要您说if(errno == ENOENT) { ... }
之类的内容,这并不会引起您的注意。但你可能不应该尝试做int errno_ptr = &errno;
。perror()
和strerror()
等函数来获取与errno
值对应的人类可读错误字符串。但是,是的,你得到的字符串通常是&#34;没有这样的文件或目录&#34;。我知道将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
永远存在;有数以千万计的代码行使用它;它基本上还很方便;它已经来不及修复&#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
可以是E2BIG
,EACCES
,EFAULT
... 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
包括在内。
您可能希望阅读可免费下载的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
。