如何检查errno的值?

Han*_*ana 7 c errno system-calls

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

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

int res;
res = systemCall();
if (res == -1)
{
    if (errno == ENOMSG)
    {
        doSomething();
    }
    else
    {
        doSomethingElse();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

至于strerro - 如果它是我需要的,我不是如何使用它,因为在这里它说实际的字符串与错误不同.从手册页引用:"(例如,如果errnum是EINVAL,则返回的描述将是"Invalid argument")".

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

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

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

Ste*_*mit 11

如何检查以下值errno:

  1. 你需要#include <errno.h>.
  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");
}
Run Code Online (Sandbox Code Playgroud)

但是不要这样做.相反

errno = 0;
int retval = printf("Hello, world!\n");
if(retval < 0) {
    fprintf(stderr, "printf failed!\n");
}
Run Code Online (Sandbox Code Playgroud)

原因是,在printf完成其工作的某个过程中,可能已经做了一些导致错误的事情,一些设置errno,但printf可能已从该错误中恢复并继续成功完成.

如果没有错误(我想一个例子可能是),有一些库函数可以保证不会触及errno atoi,但总的来说,这是你必须要小心的.

更多地谈论#4. errno看起来像一个变量,更具体地说,它看起来像一个全局变量.但当然全局变量都很糟糕.但是errno一直存在; 有数以千万计的代码行使用它; 它基本上还很方便; 现在"修理"它已经太晚了.所以,相反,如果你偷看幕后,你会发现大多数实现都是这样的

extern int __errno_pointer;
#define errno (*__errno_pointer)
Run Code Online (Sandbox Code Playgroud)

要么

extern int *__errno_pointer_function();
#define errno (*__errno_function())
Run Code Online (Sandbox Code Playgroud)

通过这种方式,errno即使在多线程代码中,它们也可以安排合理地正常工作.


Bas*_*tch 10

我假设您使用的是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); 
  };
};
Run Code Online (Sandbox Code Playgroud)

声明if (errno == ENOMSG)......有效吗?

是的; 你想errno 在一些系统调用失败后(例如何时siz<0)进行测试.

有这样的变量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).

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


P__*_*J__ 5

包括 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 */
Run Code Online (Sandbox Code Playgroud)

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