在 Linux 系统编程中,dup 和 dup2 是两个非常重要的系统调用,广泛应用于 标准输入/输出重定向、管道通信 和 文件描述符管理 等场景。本文将详细讲解这两个函数的区别、用法,并结合实际代码示例说明它们如何单独使用与配合使用。
一、基础知识:文件描述符(File Descriptor)
在 Unix/Linux 中,一切皆文件。文件、终端、套接字等 I/O 资源都用一个非负整数标识,这个整数就叫做文件描述符。
系统预定义了三个标准文件描述符:
名称 | 文件描述符 | 含义 |
---|---|---|
stdin | 0 | 标准输入 |
stdout | 1 | 标准输出 |
stderr | 2 | 标准错误输出 |
二、dup 和 dup2 的区别概览
项目 | dup | dup2 |
---|---|---|
作用 | 复制文件描述符 | 将一个文件描述符复制到指定的目标描述符 |
返回值 | 最小可用的新文件描述符编号 | 返回目标文件描述符 |
是否可指定目标 | 否,只能自动选择 | 是,第二个参数指定目标 fd |
是否关闭原 fd | 否 | 是(如果目标 fd 已打开,会先关闭它) |
三、dup 用法详解
函数原型
int dup(int oldfd);
功能
复制 oldfd 的文件描述符,返回一个新的描述符,它和 oldfd 指向相同的文件/设备,共享文件偏移量和状态。
示例:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("example.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
int newfd = dup(fd);
write(fd, "Hello ", 6);
write(newfd, "World\n", 6); // 实际写入文件的是 "Hello World"
close(fd);
close(newfd);
return 0;
}
说明fd 和 newfd 都指向同一个文件,写入时共享文件偏移量,newfd 写入内容会继续跟在 fd 的后面。
四、dup2 用法详解
函数原型:
int dup2(int oldfd, int newfd);
功能:
将 oldfd 的复制内容复制到 newfd 上。如果 newfd 已打开,则先关闭它。最终 newfd 和 oldfd 指向相同的文件。
代码示例:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
dup2(fd, STDOUT_FILENO); // 将 stdout 重定向到 log.txt
printf("这条信息将写入文件 log.txt\n");
close(fd);
return 0;
}
说明:重定向后,printf 实际写入的是文件,而不是终端。
五、配合使用:备份和恢复输出流
在实际开发中,经常需要临时重定向输出到文件,然后再恢复原本的终端输出。这时我们可以配合使用 dup 和 dup2。
示例:将标准输出重定向到文件,再恢复
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
// 打开文件准备重定向
int fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) return 1;
// 备份标准输出(终端)
int saved_stdout = dup(STDOUT_FILENO);
// 重定向 stdout 到文件
dup2(fd, STDOUT_FILENO);
printf("这行输出到文件 output.txt\n");
// 恢复 stdout 到终端
dup2(saved_stdout, STDOUT_FILENO);
printf("这行输出回到了终端\n");
close(fd);
close(saved_stdout);
return 0;
}
解释:
dup(STDOUT_FILENO):先备份标准输出(终端)。
dup2(fd, STDOUT_FILENO):重定向输出到文件。
dup2(saved_stdout, STDOUT_FILENO):再恢复回原来的终端输出。
六、总结
使用场景 | 推荐用法 |
---|---|
简单复制描述符 | dup |
需要指定目标描述符 | dup2 |
临时重定向输出 | dup + dup2 配合使用 |
注意
dup 只负责复制,不关闭任何描述符。
dup2 在复制前会自动关闭目标 newfd,防止泄漏。
所有共享描述符共享文件偏移和状态,关闭任意一个不影响其他,但最后都应关闭以避免资源泄露。