一个名为 get1
的 C 语言简单测试程序:
#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
?
strtol()
和相关函数之前将errno
设置为0,并在调用后将其与0进行比较,才能检测到溢出。 - chqrliestrtol()
即使出现溢出也会解析所有数字,因为没有无效字符。 - Stargateurgetchar()
,那么errno
就不会被设置。因此,无论导致这种情况的不幸事件的细节如何,最终都是getchar()
导致了errno
被设置。 - Mark Adler