同一进程中两次调用dup2出现输出乱码问题求助
多次dup2后读取乱码的问题分析与修复
你的程序在多次调用dup2后出现乱码,核心问题出在标准IO的缓冲机制和文件描述符的处理逻辑上,具体原因和修复方案如下:
问题根源
子进程输出未写入管道
子进程中printf("blbl")执行后,stdout在被重定向到管道时会从行缓冲变为全缓冲模式,此时输出内容停留在用户态缓冲区,未写入管道就关闭了文件描述符,导致父进程从管道读取不到有效数据,进而出现乱码或空输出。冗余文件描述符未关闭
父进程执行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
相关产品推荐
相关产品推荐

