You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pipe()与fork()使用问题:/bin/cat报Bad file descriptor错误

咱们一步步拆解你代码里的问题,然后帮你实现「通过管道在子进程间传值并修改」的需求~

你的代码里的核心问题

1. 管道根本没创建!

你定义了fd1[2]但完全没调用pipe(fd1)初始化管道!这会导致文件描述符都是无效值,后续的dup2和读写操作自然会抛出「Bad file descriptor」错误,这也是/bin/cat报错的核心原因。

2. 对fork()后变量的误解

fork()执行后,每个子进程都会拿到父进程地址空间的独立副本——也就是说,子进程1里的line和子进程2里的line是完全不相干的两个变量。你在子进程2里直接line++,修改的只是自己进程里的局部变量,根本没用到管道传递过来的值。

3. 子进程2的逻辑顺序完全错了

你先做了line++和printf,才把管道读端重定向到标准输入,之后调用cat——但cat是从标准输入读内容再输出,而你根本没从管道里读取子进程1发送的数据,更别说修改它了。

4. 父进程没等子进程跑完就退出

父进程直接exit(0),没调用wait()或waitpid()等待子进程完成,可能导致子进程还没执行完,父进程就退出了,引发输出混乱或者僵尸进程。

修正后的代码实现

下面是修改后的代码,完美实现「子进程1传值到管道,子进程2读取后修改输出」的需求:

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

#define READ_END 0
#define WRITE_END 1

int main() {
    int fd1[2];
    // 第一步:必须先创建管道!
    if (pipe(fd1) == -1) {
        perror("pipe failed");
        exit(EXIT_FAILURE);
    }

    int line = 1;
    // 子进程1:把数值转成字符串写入管道
    if(fork() == 0) {
        close(fd1[READ_END]); // 子进程1不需要读端,直接关闭
        char buffer[100];
        snprintf(buffer, sizeof(buffer), "%d", line);
        write(fd1[WRITE_END], buffer, strlen(buffer));
        close(fd1[WRITE_END]);
        exit(EXIT_SUCCESS);
    }

    // 子进程2:读取管道数据,修改后输出
    if (fork() == 0) {
        close(fd1[WRITE_END]); // 子进程2不需要写端,直接关闭
        char buffer[100];
        ssize_t bytes_read = read(fd1[READ_END], buffer, sizeof(buffer)-1);
        if (bytes_read == -1) {
            perror("read failed");
            exit(EXIT_FAILURE);
        }
        buffer[bytes_read] = '\0'; // 手动补字符串结束符

        // 把读取到的字符串转成整数,修改后输出
        int received_num = atoi(buffer);
        received_num++;

        printf("子进程1发送的值:%d\n", atoi(buffer));
        printf("子进程2修改后的值:%d\n", received_num);

        close(fd1[READ_END]);
        exit(EXIT_SUCCESS);
    }

    // 父进程:关闭管道两端,等待所有子进程执行完毕
    close(fd1[READ_END]);
    close(fd1[WRITE_END]);
    wait(NULL); // 等待第一个子进程
    wait(NULL); // 等待第二个子进程

    return 0;
}

关键修改点说明

  • 初始化管道:添加了pipe(fd1)调用,并检查返回值确保管道创建成功,这是管道通信的基础。
  • 子进程1直接写管道:用write()直接写入数据,比printf更可靠(printf有缓冲机制,可能导致数据没及时发送到管道)。
  • 子进程2读取并修改:先从管道读取子进程1的传值,转成整数后修改,再输出——这才是真正利用管道传递并修改值的逻辑。
  • 父进程等待子进程:调用两次wait(NULL)确保子进程都执行完再退出,避免输出混乱和僵尸进程。

关于你尝试的/bin/cat

如果只是想验证管道数据,你可以让子进程2把管道读端重定向到标准输入后调用cat,这样cat会直接输出管道里的内容,但cat只能读取输出,无法修改数据。如果要实现修改逻辑,必须自己处理读取、转换、修改的步骤,就像上面的代码那样。

内容的提问来源于stack exchange,提问作者kirito kun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 10:53:12