【问题标题】:cat breaks the program, manual stdin input doesn'tcat 会破坏程序,手动输入标准输入不会
【发布时间】:2017-09-02 20:30:33
【问题描述】:

我有这个小程序:

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

int main() {
    int orig = 1;
    for (int i = 0; (i != 3) && orig; ++i) {
        orig = orig && fork();
    }
    if (orig) {
        for (int i = 0; i != 3; ++i) {
            wait(NULL);
        }
    } else {
        int num;
        scanf("%8d", &num);
        printf("%d\n", num*num);
    }
}

这应该简单地平方从stdin 读取的三个数字。如果我自己输入数字,它会起作用:

akiiino$ ./out.out
12345678
12345678
12345678
260846532
260846532
260846532

但如果我将 cat 用于相同目的,它不会按预期工作:

akiiino$ cat in.txt
12345678
12345678
12345678

akiiino$ cat in.txt | ./out.out
260846532
0
0

这种奇怪行为背后的原因是什么,是否可以修复?我一直认为cating 文件与将它们输入stdin 没有什么不同。

【问题讨论】:

    标签: c shell fork stdin cat


    【解决方案1】:

    不同之处在于,当您手动输入 3 个数字 时,您是从终端读取,而低级读取在换行符处终止。让我们看看幕后发生了什么。

    1. 手动输入:

      • 3 个孩子已经开始,正在等待输入
      • 你输入一个数字和一个新行
      • 底层的read 调用被换行符终止,因为您是从终端读取的
      • 第一个孩子(得到读取的那个)有其scanf 调用解码输入并进行处理

      好的,我们对另外两个孩子进行相同的迭代

    2. 从文件或管道中读取

      • 3 个孩子已经开始,正在等待输入
      • 3 个数字和换行符立即可用
      • 第一个孩子的底层 read 读取并使用 stdio 缓冲区中的所有输入
      • 第一个孩子(得到读取的那个)有其scanf 调用解码(第一部分)输入并进行处理

      但现在其他 2 个孩子正在从位于文件末尾的文件/管道中读取。他们的 scanf 返回 0 但你无法控制它,他们让num 中的初始未确定值。

    您可以通过在循环前添加sleep(10) 来控制这不是竞争条件的问题,启动程序在第一个孩子开始阅读之前手动输入 3 个数字。由于低级读取将换行终止(特殊 tty 情况),即使在第一次读取之前 3 行可用,您仍然会得到与第一种情况相同的输出。

    【讨论】:

      【解决方案2】:

      @Some 程序员老兄已经说过,问题出在fork 命令上。 如果您尝试./out.out &lt; in.txt,它应该可以正常工作。

      【讨论】:

      • 奇怪,它对我来说很好用(猫 + 管道的奇怪行为,fork,则让孩子进行微积分。您还应该更改输出的数据类型,int 肯定不足以输入 8 位数字。
      猜你喜欢
      • 2022-01-24
      • 2021-07-28
      • 1970-01-01
      • 1970-01-01
      • 2017-01-27
      • 2016-01-21
      • 2010-10-27
      • 2021-04-29
      • 2020-03-29
      相关资源
      最近更新 更多