如何检查errno的值?

问题描述:

我正在使用系统调用,如果它失败,我需要为不同的errnos做不同的事情。如何检查errno的值?

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

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声明中应该包含哪些内容?

+1

在什么操作系统上?什么确切的系统调用?什么C库?请**编辑您的问题以改进它** –

+1

每个系统调用都有一个可能的errno值列表(请参阅它的'man'页面),这会让您知道您应该测试什么。 – Myst

+1

你写的很好。请记住,没有库函数将'errno'设置为零,除非函数指示错误并且记录为设置'errno',否则不应该对其进行测试。请注意,许多pthreads函数不会设置“errno”,例如;他们会返回错误号码。此外,即使成功,函数也可以将'errno'设置为非零值。例如,在Solaris上,如果标准输出不是终端,即使'printf()'调用成功,'errno'也可以设置为ENOTTY。 –

我假设你正在使用Linux,我想,你不直接使用系统调用,但在syscalls(2)一些(简单)包装(从C库)的上市。请注意,一些奇怪的系统调用未被C库包装(一个众所周知的未包装系统调用的示例应该是sigreturn(2),您可能不应该使用它)。 C库通常是GNU glibc,但它可能是musl-libc等。另请注意,内核原始系统调用与普通C函数有不同的calling conventions(因此实际上需要libc包装,并负责处理errno)。还请注意,errno(3)通常是一个宏(几乎像一些变量一样)。

msgrcv(2)手册页文档errno可能是E2BIG之一,EACCESEFAULT ... ENOMSGENOSYS ...(指的是男人页面获得所有可能的错误列表)。

所以,你会编写类​​似

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) ....有效吗?

是的,您只想在某些系统调用失败后(例如siz<0)测试errno

是否有这样一个变量errno

没有更多。请仔细阅读errno(3)文件。你不应该声明extern int errno;(这是有可能在20世纪80年代,而不是在21 ST世纪),但你应该总是#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)

+0

高级Linux编程下载链接可能已损坏或已过时。似乎没有为我工作。 –

+0

更正,今天有一些随机链接工作。其实,如果你能负担得起,更好地阅读一本新书。 –

+0

感谢您的领导!我会寻找更新的东西。如果想到任何事情,会很乐意听到建议。 –

包含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 */ 

你的实现可能有更多的errno包括,例如像/usr/include/asm-generic/errno.h

如何检查errno值:

  1. 您将需要#include <errno.h>
  2. 是的,你绝对可以说像if(errno == ENOENT) { ... }这样的事情,这是做这件事的常用方法。
  3. 一般来说,做而不是使用errno来确定发生了错误。检查函数的返回值,如果返回值指示错误,则检查errno以查看错误是什么。 (更多关于下面的内容。)
  4. errno看起来像一个变量,但它实际上不是。只要你说出像if(errno == ENOENT) { ... }这样的东西,这就不关你了。但你可能不应该尝试做类似​​的事情。
  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),但总的来说,这是你必须要小心的东西。

再说一点关于#4的内容。errno看起来像一个变量,更具体地说,它看起来像一个全局变量。但是,当然全球变量是不好的。但是errno已经存在了,有数千万行代码使用它;它仍然基本上非常方便; “修复”它为时已晚。所以,相反,如果你偷看了幕后,你会发现,大多数实现这样做

extern int __errno_pointer; 
#define errno (*__errno_pointer) 

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

通过这种方式,他们可以安排errno合理正常甚至工作例如,多线程代码。