`getchar()` returns 错误的特殊情况是什么?

What are the particular cases `getchar()` returns error?

所以我知道 getchar() returns EOF 当输入结束或发生错误时。我也知道我可以检查 ferror(stdin)feof(stdin) 发生了哪些情况。 我想知道特别是在什么情况下会出现错误。

我查看了这两个函数的手册页,但那里什么也没有。

所有 stdio.h 都指向一个叫做 错误指示器 的东西,它是一个内部变量,据说位于应用程序程序员拥有的不透明 FILE 对象中无法访问(参见 C17 7.21.1)。

getchar 的文档可在 C17 7.21.7.6 中找到:

The getchar function returns the next character from the input stream pointed to by stdin. If the stream is at end-of-file, the end-of-file indicator for the stream is set and getchar returns EOF. If a read error occurs, the error indicator for the stream is set and getchar returns EOF.

所以我们不知道 getchar 返回 EOF 是因为它到达了流的末尾,还是因为存在读取错误。为了知道,我们必须检查错误指示器。

这就是 ferror(stdin) 的用武之地。它是一个稍微有用的函数,因为它只执行此操作 (C17 7.21.10.3):

The ferror function returns nonzero if and only if the error indicator is set for stream.

仅此而已 - 这是一个标准化的、可移植的抽象层,我们无法真正了解幕后发生的事情。这很好,因为大多数时候我们根本不在乎。

在这些标准 C 函数下会有一个 OS-特定的 API,如果是 POSIX 可能 read(),如果是 Windows 可能 ReadFile() 等。这些函数又可能因多种原因而失败:文件句柄不正确,文件被另一个进程占用,OS 授予用户的文件没有读取权限等等。

理论上 getchar 也可以连接到嵌入式系统上的串行总线,在这种情况下,失败的原因与托管系统上的原因完全不同。现在我们突然谈论错误的波特率、缓冲区溢出、帧错误或任何适用的问题。

getchar() 可以 return EOF 用于多个系统特定的 I/O 错误。 getchar() 被定义为等同于 getc(stdin),它本身等同于 fgetc(stdin),只是它可以作为宏来实现。以下是 linux man page 中 linux 系统的可能原因列表:

RETURN VALUE

Upon successful completion, fgetc() shall return the next byte from the input stream pointed to by stream. If the end-of-file indicator for the stream is set, or if the stream is at end-of- file, the end-of-file indicator for the stream shall be set and fgetc() shall return EOF. If a read error occurs, the error indicator for the stream shall be set, fgetc() shall return EOF, and shall set errno to indicate the error.

ERRORS

The fgetc() function shall fail if data needs to be read and:

EAGAIN The O_NONBLOCK flag is set for the file descriptor underlying stream and the thread would be delayed in the fgetc() operation.

EBADF The file descriptor underlying stream is not a valid file descriptor open for reading.

EINTR The read operation was terminated due to the receipt of a signal, and no data was transferred.

EIO A physical I/O error has occurred, or the process is in a background process group attempting to read from its controlling terminal, and either the calling thread is blocking SIGTTIN or the process is ignoring SIGTTIN or the process group of the process is orphaned. This error may also be generated for implementation-defined reasons.

EOVERFLOW The file is a regular file and an attempt was made to read at or beyond the offset maximum associated with the corresponding stream.

The fgetc() function may fail if:

ENOMEM Insufficient storage space is available.

ENXIO A request was made of a nonexistent device, or the request was outside the capabilities of the device.