C - 如何在只读取单个字符时检测管道中的 EOF?

C - How to detect EOF in pipe when reading only single char?

this 回答中所述,我希望 reader 进程 在 [= 之后立即捕获 EOF 21=]writer 进程 关闭所有相关的文件描述符。

但这并没有发生,这个程序最终陷入了无限循环。 Parent 等待它 child 完成 & child 等待 EOF 发出关闭管道的信号。

为什么 reader 进程没有收到 EOF

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>

#define STRING_TO_SEND "Hello, world!\n"

int main() {
    int fd[2], i = 0;
    __pid_t pid;
    char _char;
    ssize_t nbytes;

    pipe(fd);
    pid = fork();

    if (pid == -1) {
        // Error
        perror("Error forking!");
        return EXIT_FAILURE;

    } else if (pid == 0) {

        // Child
        close(fd[1]);
        while ((nbytes = read(fd[0], &_char, 1)) != EOF) {
            if (nbytes == 0)
                continue;
            putchar(_char);
        }
        close(fd[0]);

    } else {

        // Parent
        close(fd[0]);

        for(;;) {
            _char = STRING_TO_SEND[i++];
            write(fd[1], &_char, 1);
            if (_char == '[=10=]')
                break;
        }

        close(fd[1]);
        close(STDOUT_FILENO);

        while (wait(NULL)>0) {}
    }
    return 0;
}

您只是误解了 read() 的 "end of file" 指示,它只是意味着 read() 不再需要阅读(在这种情况下,read() returns 0)。但是 read() 实际上 return EOF。所以你的条件应该是:

while ((nbytes = read(fd[0], &_char, 1)) > 0) {

另外 __pid_t 是您的 C 库的内部类型。你不应该使用它;只需使用 pid_t.

有关详细信息,请参阅 read(2) 的手册页。

EOF 是一个常量,通常定义为 -1,stdio(原始系统调用周围的 C 库缓冲层)用于在 getchar() 等函数中发出文件结束信号它将 returned 字符与文件结束信号混为一谈。

read 通过简单地 returning 0 发出文件结束信号。请注意,如果出现错误,它也可以 return -1(例如,如果读取在读取任何内容之前被信号处理程序中断,您可以获得 EINTR)。

因此,您想要的是:

while ((nbytes = read(fd[0], &_char, 1)) > 0){ /*...*/ }
if (0>nread) { /*report error (or maybe repeat if it's EINTR)*/ }

联机帮助页(read(2)) or the POSIX spec for read 记录所有这些内容。