使用 scanf() 的管道意外行为

Unexpected behavior of pipes with scanf()

自从我上次用 C 编程以来已经有一段时间了,我在使管道工作时遇到了问题。 (为了清楚起见,我在 Windows 7 上使用 Cygwin。)特别是,我需要帮助理解以下示例的行为:

/* test.c */

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


int main() {

    char c;
    //scanf("%c", &c); // this is problematic

    int p[2];
    pipe(p);

    int out = dup(STDOUT_FILENO);

    // from now on, implicitly read from and write on pipe
    dup2(p[0], STDIN_FILENO);
    dup2(p[1], STDOUT_FILENO);

    printf("hello");
    fflush(stdout);

    // restore stdout
    dup2(out, STDOUT_FILENO);
    // should read from pipe and write on stdout
    putchar(getchar());
    putchar(getchar());
    putchar(getchar());
}

如果我调用:

echo abcde | ./test.exe

我得到以下输出:

hel

但是,如果我取消注释 scanf 调用,我会得到:

bcd

我无法解释。这实际上是具有 fork/exec 结构的更复杂程序的非常简化版本,该程序开始表现非常糟糕。尽管没有循环,但它以某种方式开始在无限循环中产生无限 children。因此,如果规则允许,我可能需要用更具体的使用案例来扩展问题。非常感谢。

流I/O函数如scanf一般会执行缓冲以提高性能。因此,如果您在标准输入上调用 scanf,那么它可能会读取比满足请求所需的更多的字符,并且额外的字符将等待、缓冲以供下一次读取。

换出底层文件描述符不会影响之前缓冲的数据。当您随后再次读取该文件时,您会在第一次缓冲数据,直到这些数据用完,然后才能从新的基础文件中获取新数据。

如果您愿意,可以在对流执行任何 I/O 操作之前通过 setvbuf() 函数关闭流的缓冲:

int result = setvbuf(stdin, NULL, _IONBF, 0);
if (result != 0) {
    // handle error ...
}

This is actually a very simplified version of a more complex program with a fork/exec structure that started behaving very bad. Despite not having cycles, it somehow began spawning infinite children in an endless loop.

我不明白这种行为与你在这里提出的问题有什么关系。

So, rules permitting, I'll probably need to extend the question with a more concrete case of use.

那将是一个单独的问题。