c - 为什么从数据集的/dev 源成功读取 errno?

标签 c linux macos stdio errno

用 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/

相关文章:

c - caddr_t有什么意义,什么时候用?

无法访问C中二维数组的位置

c++ - 如何将 C++ 代码转换为 C

linux - 通过脚本中的参数将多个文本文件连接到 Bash 中的单个文件中

c++ - 在成员函数中使用 'delete this' 后,我可以访问其他成员函数。为什么?

LINUX:如何输出 SQL 脚本中使用的表

swift - 切换出嵌入在 NSContainerView 中的 View

c# - 在 C# 中使用 C/内联汇编

macos - 如何在 Mac OS X 10.6 上升级到 Autoconf 2.6.2 或更高版本?

swift - SceneKit Cocoa快照声明失败