【问题标题】:Read an entire pipe - c读取整个管道 - c
【发布时间】:2018-10-04 20:38:01
【问题描述】:

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

#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;
}

如果你知道我该如何处理这个问题,请解释一下。

【问题讨论】:

  • 如何处理此类问题是现在开始学习如何使用调试器。我不是油嘴滑舌:这是诊断和解决您自己的问题的基本技能,而无需等待互联网上的人为您做这件事。 ;-)
  • fgetc() 的参数是FILE *。您的代码通过int。这引入了未定义的行为。此外,fgetc() 返回 int,而不是 char。最后,有很多很好的解释说明为什么 while (!feof()) 样式循环是不好的技术 - 谷歌会帮你找到一个。

标签: c pipe dup2 feof


【解决方案1】:

pipe 函数返回的是一对 int 文件描述符,而不是 FILE 文件描述符。这意味着您可以在它们上使用readwriteclose,但既不能使用fgetc,也不能使用feof

此外,while(!feof(file))(几乎)总是wrong,因为在不成功的读取到达文件末尾之后设置了标志。

这还不是全部。当写入端的所有描述符都关闭时,您只会在管道的读取端获得 EOF。所以你必须关闭或刷新stdout以确保所有字符都已写入管道,如果你还没有关闭stdout,则关闭文件描述符1,并关闭tube[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);
}

它修复了在不是FILE的东西上使用feoffgetc引起的SEGFAULT,并确保在读取文件内容之前正确关闭文件的写端以获得良好的文件结束条件。

【讨论】:

【解决方案2】:

但是,我得到一个段错误。 ? 这意味着您没有正确阅读编译器警告。当您执行feof(tube[0]) 时,它说feof() 需要FILE*,但您提供了inttube[0] 是inetger)类型。

/usr/include/stdio.h:828:12:注意:预期的“struct FILE *”但是 参数的类型是“int”

所以第一件事总是阅读编译器警告并使用-Wall 标志编译代码。

这个fgetc(tube[0]);不是从file descriptor读取数据的方式,使用read()系统调用从文件描述符而不是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 了解这些系统调用的工作原理..

【讨论】:

    【解决方案3】:

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

    试试:

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

    【讨论】:

    • 我总是遇到段错误。但是,是的,这是一个误解(因此我更新了主帖)。谢谢
    • feof() 和 fgetc() 都期望指向流的指针,而不是文件描述符。尝试使用 fpopen() 创建一个流。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-16
    • 2011-07-23
    • 2020-08-14
    • 1970-01-01
    • 2012-06-13
    相关资源
    最近更新 更多