如何将数据传递给在Linux中调用scanf()和read()的程序

IGN*_*ius 6 c unix linux pipe

我有一个C程序,看起来像这样:

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

int main()
{
    int n;
    char str[16];
    scanf("%d", &n);
    printf("n: %d\n", n);

    int count = read(STDIN_FILENO, str, 16);
    printf("str: %s\n", str);
    printf("read %d bytes\n", count);
}
Run Code Online (Sandbox Code Playgroud)

如果我使用类似命令将数据传输到此程序中

(echo -en '45\n'; echo -en 'text\n') | ./program

scanf()实际上只读取数据.read()只需读取0个字节.

换句话说,程序输出

n: 45
str:
read 0 bytes

我怎么能管到的数据都scanf()read()

编辑:对不起,我应该澄清:我正在寻找一种方法来做到这一点,而无需修改源代码.感谢那些回答和评论的人.

Mar*_*ian 4

完全不建议对同一个文件描述符同时使用文件描述符函数(read)和流函数(scanf)。使用FILE *(即 fread/fprintf/scanf/...)的函数正在缓冲数据,而使用文件描述符(即read/write/...)的函数不使用这些缓冲区。对于您的情况,修复程序的最简单方法是使用fread而不是read. 该程序可能如下所示:

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

int main() {
  int n;
  char str[16];
  scanf("%d", &n);
  printf("n: %d\n", n);

  int count = fread(str, 16, 1, stdin);
  printf("str: %s\n", str);
  printf("read %d bytes\n", count);
}
Run Code Online (Sandbox Code Playgroud)

在您的原始示例中,scanf已读取前面的输入并将其存储在缓冲区中。因为输入非常短并且可以立即使用,所以它被完全读取到缓冲区中,并且您的调用read没有更多内容可读取。

当您直接从终端输入输入时,不会发生这种情况,因为scanf从终端设备读取时不会缓冲超出一行的数据。如果您在管道输入中创建时间暂停(例如通过命令),也不会发生这种情况:

(echo -en '45\n'; sleep 1; echo -en 'text\n') | ./program
Run Code Online (Sandbox Code Playgroud)