dup and dup2的剖析

时间:2022-02-17 22:48:04

转:http://www.cnblogs.com/sdphome/archive/2011/04/30/2033381.html

dupdup2都可用来复制一个现存的文件描写叙述符,使两个文件描写叙述符指向同一个file结构体。假设两个文件描写叙述符指向同一个file结构体,File
Status Flag和读写位置仅仅保存一份在file结构体中,而且file结构体的引用计数是2。假设两次open同一文件得到两个文件描写叙述符。则每一个描写叙述符相应一个不同的file结构体,能够有不同的File
Status Flag和读写位置。

请注意区分这两种情况。

#include <unistd.h>

int dup(int oldfd);
int dup2(int oldfd, int newfd);

假设调用成功,这两个函数都返回新分配或指定的文件描写叙述符,假设出错则返回-1。dup返回的新文件描写叙述符一定该进程未使用的最小文件描写叙述符,这一点和open相似。dup2能够用newfd參数指定新描写叙述符的数值。假设newfd当前已经打开,则先将其关闭再做dup2操作。假设oldfd等于newfd,则dup2直接返回newfd而不用先关闭newfd再复制。

以下这个样例演示了dupdup2函数的使用方法,请结合后面的连环画理解程序的运行过程。

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
int fd, save_fd;
char msg[] = "This is a test\n";

fd = open("somefile", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
if(fd<0) {
perror("open");
exit(1);
}
save_fd = dup(STDOUT_FILENO);
dup2(fd, STDOUT_FILENO);
close(fd);
write(STDOUT_FILENO, msg, strlen(msg));
dup2(save_fd, STDOUT_FILENO);
write(STDOUT_FILENO, msg, strlen(msg));
close(save_fd);
return 0;
}

dup and dup2的剖析

重点解释两个地方:

  • 第3幅图,要运行dup2(fd, 1);,文件描写叙述符1原本指向tty。如今要指向新的文件somefile,就把原来的关闭了,可是tty这个文件原本有两个引用计数,还有文件描写叙述符save_fd也指向它,所以仅仅是将引用计数减1。并不真的关闭文件。

  • 第5幅图。要运行dup2(save_fd, 1);,文件描写叙述符1原本指向somefile,如今要指向新的文件tty,就把原来的关闭了。somefile原本仅仅有一个引用计数,所以这次减到0,是真的关闭了。

 

样例1:

在学习dup2时总是碰到“重定向”一词。上图完毕的就是一个“从标准输出到文件的重定向”。经过dup2后进程A的不论什么目标为STDOUT_FILENO的I/O操作如printf等,其数据都将流入fd3所相应的文件里。

以下是一个例子程序

#define TESTSTR "Hello dup2\n"
int main() {
int fd3;
fd3 = open("testdup2.dat",0666)。
if (fd < 0) {
printf("open error\n");
exit(-1);
}
if (dup2(fd3,STDOUT_FILENO) < 0) {
printf("err in dup2\n");
}
printf(TESTSTR);
return 0;
}
其结果就是你在testdup2.dat中看到"Hello dup2"。

 

样例2:

#define TESTSTR "Hello dup2\n"
#define SIZEOFTESTSTR 11
int main() {
int fd3;
int s_fd;
int n_fd;
fd3 = open("testdup2.dat",0666)。
if (fd3 < 0) {
printf("open error\n");
exit(-1)。
}
/* 复制标准输出描写叙述符 */
s_fd = dup(STDOUT_FILENO);
if (s_fd < 0) {
printf("err in dup\n");
}
/* 重定向标准输出到文件 */
n_fd = dup2(fd3,STDOUT_FILENO);
if (n_fd < 0) {
printf("err in dup2\n");
}
write(STDOUT_FILENO,TESTSTR,SIZEOFTESTSTR); /* 写入testdup2.dat中 */
/* 重定向恢复标准输出 */
if (dup2(s_fd,n_fd) < 0) {
printf("err in dup2\n");
}
write(STDOUT_FILENO,TESTSTR,SIZEOFTESTSTR); /* 输出到屏幕上 */
return 0;
}
注意这里我在输出数据的时候我是用了不带缓冲的write库函数。假设使用带缓冲区的printf。则终于结果为屏幕上输出两行"Hello dup2",而文件testdup2.dat中为空。原因就是缓冲区作怪。因为终于的目标是屏幕,所以程序最后将缓冲区的内容都输出到屏幕。