如何查看errno的值?
How to check the value of errno?
我正在使用一个系统调用,如果它失败了,我需要对不同的 errnos 做不同的事情。
我需要编写如下所示的代码:
int res;
res = systemCall();
if (res == -1)
{
if (errno == ENOMSG)
{
doSomething();
}
else
{
doSomethingElse();
}
}
perror 没有帮助,因为它只打印值。
至于strerro - 如果它是我需要的,我不知道如何使用它,因为here它说实际的字符串与错误不一样。引用手册页:“(例如,如果 errnum 是 EINVAL,则返回的描述将是 "Invalid argument")”。
我正在使用 Linux。
系统调用:msgsend 和 msgrcv (https://linux.die.net/man/2/msgrcv)。我不确定你问的是什么 C 库。
我发现我没有很好地解释自己。
if (errno == ENOMSG) 语句是否有效?有没有errno这样的变量?基本上我的问题是:为了测试 errno,if
语句中应该包含什么?
包括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
。
我假设您正在使用 Linux,并且我假设您不会直接使用系统调用,而是一些(简单的)包装器(来自syscalls(2). Notice that some weird system calls are not wrapped by the C library (a well known example of unwrapped system call would be sigreturn(2) which you probably should never use). Quite often the C library is GNU glibc, but it might be musl-libc etc. Notice also that kernel raw system calls have different calling conventions than ordinary C function (so in practice a libc wrapper is required, and is in charge of dealing with errno
). Notice also that errno(3) 中列出的您的 C 库)通常是一个宏(几乎表现为某个变量)。
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);
};
};
Is the statement if (errno == ENOMSG)
.... valid?
是的,是的;您只想在某些系统调用失败后测试 errno
(例如,当 siz<0
时)。
Is there such a variable errno
?
没有了。请仔细阅读 errno(3) 文档。你不应该声明 extern int errno;
(这在 1980 年代是可能的,而不是在 21st 世纪)但你应该 always #include <errno.h>
并使用 errno
就好像它是一个变量一样,但它几乎总是一些宏(其定义出现在 /usr/include/bits/errno.h
中,它被 /usr/include/errno.h
包含)。
顺便说一句,SysV 风格的设施往往会过时并且并不总是可用。我推荐使用 POSIX 消息队列工具,阅读 mq_overview(7).
您可能想要阅读可免费下载的 Advanced Linux Programming (an old book; you can buy something better & newer) and/or all the man pages reachable from intro(2) & syscalls(2) & intro(3)。
如何查看errno
的值:
- 您将需要
#include <errno.h>
。
- 是的,您绝对可以说
if(errno == ENOENT) { ... }
之类的话,这是常见的推荐方式。
- 一般来说,做不使用
errno
来判断是发生了错误。检查函数的 return 值,如果 return 值指示错误,则检查 errno
以查看错误是什么。 (更多内容见下文。)
errno
看起来像一个变量,但实际上不是。只要你只是说 if(errno == ENOENT) { ... }
这样的话,这与你无关。但是你可能不应该尝试做像 int errno_ptr = &errno;
. 这样的事情
- 您可以使用
perror()
和 strerror()
等函数来获取与 errno
值对应的人类可读错误字符串。但是,是的,您得到的字符串通常是“没有这样的文件或目录”之类的东西。据我所知,没有什么好的方法可以将 errno 值 ENOENT
转换为字符串 "ENOENT"
。 (附录:请参阅 this question 了解一些答案。)
关于#3 多说一点。有时很想说
errno = 0;
printf("Hello, world!\n");
if(errno != 0) {
fprintf(stderr, "printf failed!\n");
}
但是不要那样做。相反做
int retval = printf("Hello, world!\n");
if(retval < 0) {
fprintf(stderr, "printf failed!\n");
}
原因是,printf
在执行其工作过程中的某个地方可能做了一些导致错误的事情,一些设置 errno
的事情,但 printf
可能已从该错误中恢复并继续成功完成。
有极少数库函数保证 不会 在没有错误的情况下触及 errno(我认为一个例子可能是 atoi
),但总的来说,这是你必须要小心的事情。
关于#4 多说一点。 errno
看起来像一个变量,更具体地说,它看起来像一个全局变量。但是当然全局变量是不好的。但是 errno
一直存在;有数千万行代码在使用它;基本上还是很方便的;现在“修复”它为时已晚。所以,相反,如果你在幕后偷看,你会发现大多数实现都在做类似
的事情
extern int __errno_pointer;
#define errno (*__errno_pointer)
或
extern int *__errno_pointer_function();
#define errno (*__errno_function())
这样,即使在多线程代码中,他们也可以安排 errno
合理地正常工作。
我正在使用一个系统调用,如果它失败了,我需要对不同的 errnos 做不同的事情。
我需要编写如下所示的代码:
int res;
res = systemCall();
if (res == -1)
{
if (errno == ENOMSG)
{
doSomething();
}
else
{
doSomethingElse();
}
}
perror 没有帮助,因为它只打印值。
至于strerro - 如果它是我需要的,我不知道如何使用它,因为here它说实际的字符串与错误不一样。引用手册页:“(例如,如果 errnum 是 EINVAL,则返回的描述将是 "Invalid argument")”。
我正在使用 Linux。 系统调用:msgsend 和 msgrcv (https://linux.die.net/man/2/msgrcv)。我不确定你问的是什么 C 库。
我发现我没有很好地解释自己。
if (errno == ENOMSG) 语句是否有效?有没有errno这样的变量?基本上我的问题是:为了测试 errno,if
语句中应该包含什么?
包括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
。
我假设您正在使用 Linux,并且我假设您不会直接使用系统调用,而是一些(简单的)包装器(来自syscalls(2). Notice that some weird system calls are not wrapped by the C library (a well known example of unwrapped system call would be sigreturn(2) which you probably should never use). Quite often the C library is GNU glibc, but it might be musl-libc etc. Notice also that kernel raw system calls have different calling conventions than ordinary C function (so in practice a libc wrapper is required, and is in charge of dealing with errno
). Notice also that errno(3) 中列出的您的 C 库)通常是一个宏(几乎表现为某个变量)。
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);
};
};
Is the statement
if (errno == ENOMSG)
.... valid?
是的,是的;您只想在某些系统调用失败后测试 errno
(例如,当 siz<0
时)。
Is there such a variable
errno
?
没有了。请仔细阅读 errno(3) 文档。你不应该声明 extern int errno;
(这在 1980 年代是可能的,而不是在 21st 世纪)但你应该 always #include <errno.h>
并使用 errno
就好像它是一个变量一样,但它几乎总是一些宏(其定义出现在 /usr/include/bits/errno.h
中,它被 /usr/include/errno.h
包含)。
顺便说一句,SysV 风格的设施往往会过时并且并不总是可用。我推荐使用 POSIX 消息队列工具,阅读 mq_overview(7).
您可能想要阅读可免费下载的 Advanced Linux Programming (an old book; you can buy something better & newer) and/or all the man pages reachable from intro(2) & syscalls(2) & intro(3)。
如何查看errno
的值:
- 您将需要
#include <errno.h>
。 - 是的,您绝对可以说
if(errno == ENOENT) { ... }
之类的话,这是常见的推荐方式。 - 一般来说,做不使用
errno
来判断是发生了错误。检查函数的 return 值,如果 return 值指示错误,则检查errno
以查看错误是什么。 (更多内容见下文。) errno
看起来像一个变量,但实际上不是。只要你只是说if(errno == ENOENT) { ... }
这样的话,这与你无关。但是你可能不应该尝试做像int errno_ptr = &errno;
. 这样的事情
- 您可以使用
perror()
和strerror()
等函数来获取与errno
值对应的人类可读错误字符串。但是,是的,您得到的字符串通常是“没有这样的文件或目录”之类的东西。据我所知,没有什么好的方法可以将 errno 值ENOENT
转换为字符串"ENOENT"
。 (附录:请参阅 this question 了解一些答案。)
关于#3 多说一点。有时很想说
errno = 0;
printf("Hello, world!\n");
if(errno != 0) {
fprintf(stderr, "printf failed!\n");
}
但是不要那样做。相反做
int retval = printf("Hello, world!\n");
if(retval < 0) {
fprintf(stderr, "printf failed!\n");
}
原因是,printf
在执行其工作过程中的某个地方可能做了一些导致错误的事情,一些设置 errno
的事情,但 printf
可能已从该错误中恢复并继续成功完成。
有极少数库函数保证 不会 在没有错误的情况下触及 errno(我认为一个例子可能是 atoi
),但总的来说,这是你必须要小心的事情。
关于#4 多说一点。 errno
看起来像一个变量,更具体地说,它看起来像一个全局变量。但是当然全局变量是不好的。但是 errno
一直存在;有数千万行代码在使用它;基本上还是很方便的;现在“修复”它为时已晚。所以,相反,如果你在幕后偷看,你会发现大多数实现都在做类似
extern int __errno_pointer;
#define errno (*__errno_pointer)
或
extern int *__errno_pointer_function();
#define errno (*__errno_function())
这样,即使在多线程代码中,他们也可以安排 errno
合理地正常工作。