读取整个管道 - c

Read an entire pipe - c

提问人:ztarky 提问时间:4/24/2018 最后编辑:Jonathan Lefflerztarky 更新时间:6/16/2019 访问量:5785

问:

我在这段代码上遇到了一些困难。 我需要从管道末端获取所有信息。 但是,我收到一个段错误。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

int main(void){

    int tube[2];

    if(pipe(tube) == -1){
        perror("Erreur");
        exit(1);
    }

    dup2(tube[1],1);

    printf("Few lines \n");
    printf("of an undefined size. \n");

    while (!feof(tube[0])) {
        char temp = fgetc(tube[0]);
        printf("chaine : %c\n", temp);
    }

    return 0;
}

如果您知道我如何处理这个问题,请解释。

C DUP2 FEOF

评论

2赞 underscore_d 4/24/2018
如何处理此类问题,从现在开始学习如何使用调试器。我不是在胡说八道:这是诊断和解决你自己的问题的基本技能,而不必等待互联网上的人为你做这件事。;-)
0赞 Peter 4/24/2018
的参数是 .您的代码传递了 .这引入了未定义的行为。此外,返回 ,而不是 。最后,有很多很好的解释为什么风格循环是糟糕的技术 - 谷歌会帮助你找到一个。fgetc()FILE *intfgetc()intcharwhile (!feof())

答:

0赞 user2686305 4/24/2018 #1

你正在使用一个返回单个字符 (fgetc) 的函数,然后将该值视为指向 printf 调用中字符串的指针。您还将该字符存储为指向字符的指针的地址,而不是实际字符,因此当 printf 读取您的字符串时,它会读取一些它不拥有的低内存。fgetc 返回字符本身,你需要一个 char 变量,而不是 char*。

尝试:

while (!feof(tube[0])) {
    char temp = fgetc(tube[0]);
    printf("chaine : %c\n", temp);
}

评论

0赞 ztarky 4/24/2018
我总是遇到段错误。但是,是的,这是一个误解(因此我更新了主要帖子)。感谢
1赞 user2686305 4/24/2018
feof() 和 fgetc() 都期望指向流的指针,而不是文件描述符。尝试使用 fpopen() 创建流。
3赞 Serge Ballesta 4/24/2018 #2

函数返回的是一对 int 文件描述符,而不是 1。这意味着您可以在它们上使用 、 或,但不能使用 、 或 。pipeFILEreadwriteclosefgetcfeof

此外,(几乎)总是错误的,因为该标志是在未成功的读取到达文件末尾设置的。while(!feof(file))

这还不是全部。只有当写入端的所有描述符都关闭时,您才能在管道的读取端获得 EOF。因此,您必须关闭或刷新以确保所有字符都已写入管道,如果尚未关闭 stdout,则关闭文件描述符 1,并关闭它仍然是管道写入端的文件描述符。stdouttube[1]

因此,您可以将 while 循环替换为:

close(tube[1]);
fclose(stdout);

while (1) {
    char temp;
    if (read(tube[0], &temp, 1) < 1) break;
    fprintf(stderr, "chaine : %c\n", temp);
}

它修复了由在非 上使用 和 引起的 SEGFAULT,并确保在读取文件内容之前正确关闭文件的写入端,以获得良好的文件结束条件。feoffgetcFILE

评论

1赞 Ibrahim Mohamed 12/30/2019
如果管道仍然为空,该函数将阻止等待内容写入管道,并且该过程通常会挂起。这个答案讨论了: stackoverflow.com/a/8130971/4365678 您也可以在 pipe 的手册页中阅读它: linux.die.net/man/7/piperead()
1赞 Achal 4/24/2018 #3

但是,我收到一个段错误。?这意味着您没有正确阅读编译器警告。当你这样做时,它说期望,但你已经提供了(是inetger)类型。feof(tube[0])feof()FILE*inttube[0]

/usr/include/stdio.h:828:12:注意:应为“struct FILE *”,但 参数的类型为“int”

因此,第一件事是始终阅读编译器警告并使用标志编译代码。-Wall

这不是从中读取数据的方式,使用系统调用从文件描述符中读取数据不是。 如果您用 打开了文件,则可以使用。fgetc(tube[0]);file descriptorread()fgetc()fgetc()fopen()

dup2(tube[1],1); /* this is not expected one which you want*/

像这样使用

dup2(1,tube[1]);/*stdout get duplicated with tube[1] i.e whatever you
                        write on stdout will be written into write end of pipe*/

这是一个简单的例子。

char temp[100];
        int ret = 0;
        ret = read(tube[0],temp,sizeof(temp));/*reading from pipe*/
        if(ret == -1)   {
                perror("read");
                return 0;
        }
        else {
                temp[ret] = '\0';/*read returns no of items read, so put null
                                        at last otherwise you may get some junk data  */
                printf("%s",temp);
        }

阅读 & 以了解这些系统调用的工作原理。man 2 readman 2 dup2