用 C 编写的简单测试程序 get1
:
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void) {
errno = 0;
int ch = fgetc(stdin);
printf("ch = %d\n", ch);
if (errno)
printf("errno = %d: %s\n", errno, strerror(errno));
return 0;
}
它只打印以十进制形式读取的第一个字节,然后显示 errno
以及如果 errno
不为零则相关的错误消息。
一些结果(foo
是一个文本文件,empty
是一个长度为零的文件):
% ./get1 < foo
ch = 104
% ./get1 < empty
ch = -1
好的,正如预期的那样。然而:
% ./get1 < /dev/zero
ch = 0
errno = 25: Inappropriate ioctl for device
% ./get1 < /dev/null
ch = -1
errno = 25: Inappropriate ioctl for device
% ./get1 < /dev/random
ch = 196
errno = 25: Inappropriate ioctl for device
读取工作正常,但当我从这些设备中的任何一个读取时,它正在设置 errno
。为什么?
那是在 macOS (Darwin) 上。我在 Linux (Debian) 和 NetBSD 上得到了同样的结果,除了 /dev/random
的不同错误(其他设备上的错误与 macOS 上的错误相同):
% ./get1 < /dev/random
ch = 170
errno = 22: Invalid argument
据我了解,如果您没有得到 EOF
,那么就没有错误。如果确实得到 EOF
,则检查 errno
以查看是否有错误。在所有这些情况下,从设备获取字节似乎没有错误,也不应该有错误。然而 errno
已设置。
(删除 printf
不会改变任何东西,以防有人想知道。)
事实证明,在 AIX、SunOS 或 OpenSUSE 上从此类设备读取时,errno
未设置。
那么这里有什么交易?这是一个错误,尽管很普遍?这是可以接受的行为吗?这是预期的行为吗?为什么要设置errno
?
最佳答案
errno
不是特定操作的结果,而是构建高级 FILE *stdin
stdio 结构时支持操作的结果。
Libc 通常调用 stat()
,少数其他调用和 lseek()
系统调用失败,因为 /dev/
中的特定文件是不是常规文件。它可能取决于特定的 Libc 实现,因此您在各种系统上看到的差异。
但这并不意味着您的操作失败,您应该仅在返回错误代码时检查 errno。
在 Linux 上,您可以使用命令 strace
来获取您的程序正在调用的所有系统调用的列表以及导致错误号的确切系统调用:
strace ./my program
其他系统上也有类似的工具。
关于c - 为什么从数据集的/dev 源成功读取 errno?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41436509/