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

同一进程中两次调用dup2出现输出乱码问题求助

多次dup2后读取乱码的问题分析与修复

你的程序在多次调用dup2后出现乱码,核心问题出在标准IO的缓冲机制和文件描述符的处理逻辑上,具体原因和修复方案如下:

问题根源

  1. 子进程输出未写入管道
    子进程中printf("blbl")执行后,stdout在被重定向到管道时会从行缓冲变为全缓冲模式,此时输出内容停留在用户态缓冲区,未写入管道就关闭了文件描述符,导致父进程从管道读取不到有效数据,进而出现乱码或空输出。

  2. 冗余文件描述符未关闭
    父进程执行dup2(f, 0)后,未关闭原文件描述符f,虽然stdin已经指向目标文件,但冗余的文件描述符可能引发资源泄漏或后续IO操作的异常;同时管道读端在dup2后也未及时关闭,增加了不必要的资源占用。

修复后的代码

#define BSIZE 256
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>

const char in[] = "i.txt";

int main(){
    int id, fd[2];
    if (pipe(fd) == -1) {
        perror("pipe failed");
        exit(EXIT_FAILURE);
    }
    id = fork();
    if(id == 0){
        close(fd[0]);
        // 将stdout重定向到管道写端
        dup2(fd[1], STDOUT_FILENO);
        // 用换行触发行缓冲刷新,或手动调用fflush(stdout)
        printf("blbl\n");
        close(fd[1]);
        // 子进程用_exit直接退出,避免刷新其他缓冲区
        _exit(EXIT_SUCCESS);
    }
    else if(id > 0){
        close(fd[1]);
        char tmp[BSIZE];
        int f = open(in, O_RDONLY);
        if(f == -1){
            perror("open file failed");
            exit(EXIT_FAILURE);
        }
        // 重定向stdin到文件,关闭原文件描述符
        dup2(f, STDIN_FILENO);
        close(f);
        if(fgets(tmp, BSIZE, stdin) != NULL){
            puts(tmp);
        }
        // 重定向stdin到管道读端,关闭原管道读端
        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);
        if(fgets(tmp, BSIZE, stdin) != NULL){
            puts(tmp);
        }
        wait(NULL);
    }
    else{
        perror("fork failed");
        exit(EXIT_FAILURE);
    }
    return 0;
}

关键修复点

  • 强制刷新子进程输出:在printf中添加\n(触发行缓冲自动刷新),或调用fflush(stdout)确保数据写入管道;子进程用_exit退出,避免触发C标准库的缓冲区刷新逻辑带来的意外。
  • 及时关闭冗余文件描述符:每次dup2完成后立即关闭原文件描述符,避免资源泄漏和IO冲突。
  • 增加错误判断:为pipe、fork、open等系统调用添加错误处理,提升程序鲁棒性。
  • 安全读取判断:调用fgets后先判断返回值是否为NULL,避免读取失败时输出乱码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:25:36