先上点废话...
久闻dup dup2是复制文件描述符的,但是其用法和存在的意义,一直没有细究。但从其字面上的意思来说,复制文件描述符,这个功能似乎太鸡肋,一个文件描述符不过是一个整形数字,直接拿来用不就可以了么,犯得着来一个"复制文件描述符"?
抱着疑问,一探究竟...
来到linux控制台,敲下: man dup,弹出如下框框:
原型:
int dup(oldfd);
int dup2(oldfd, newfd);
其中dup分配一个新的最小的系统未用的描述符,而dup2(oldfd, newfd)则会将旧的描述符拷贝到新的描述符。这个拷贝意味着,newfd和oldfd会共享文件的偏移和状态值。需要注意的是,dup2会首先执行close(newfd)的操作,就是切断newfd与原文件之间的联系,然后映射到oldfd所打开的文件上。需要注意的是,当oldfd是一个无效的文件描述符的时候,dup2调用失败,不会执行close(newfd)的操作。
返回值:
成功的话:则返回新的文件描述符,对于dup函数而言就是返回一个新的系统未用的最小fd, dup2就是返回参数newfd。
失败:返回-1。
举个例子:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main()
{
int oldfd = open("foo", O_CREAT|O_TRUNC|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
if (oldfd < 0)
{
printf("open foo error: %s\n", strerror(errno));
return -1;
}
printf("oldfd: %d\n", oldfd);
int newfd = dup(oldfd);
if (-1 == newfd)
{
printf("dup error: %s\n", strerror(errno));
return -1;
}
printf("newfd: %d\n", newfd);
char *buf = "hello 123\n";
int size = strlen(buf);
if (write(newfd, buf, size) != size)
printf("write error: %s\n", strerror(errno));
else
printf("write ok\n");
close(newfd);
close(oldfd);
newfd = 0;
oldfd = 8;
newfd = open("foodup2", O_CREAT|O_TRUNC|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO);
if (newfd < 0)
{
printf("open foodup2 error: %s\n", strerror(errno));
return -1;
}
printf("newfd: %d\n", newfd);
int ret = dup2(newfd, oldfd);
if (-1 == newfd)
{
printf("dup error: %s\n", strerror(errno));
return -1;
}
printf("return ret: %d, oldfd:%d\n", ret, oldfd);
if (size != write(oldfd, buf, size))
printf("write error: %d\n", strerror(errno));
close(oldfd);
close(newfd);
return 0;
}
上述代码先open了foo文件,并打印oldfd的值,当调用dup(oldfd)后,再打印newfd的值,从我的PC上输出的个
值分别是3和4,不同的机器不一样。但是很明显这是两个不同的值,往newfd写入一串数字后,oldfd对应的文件
foo会被写入这串数字。查看结果: cat foo
程序的下半段调用了dup2函数,在此之前,先把oldfd置零,newfd随便赋了一个值8。紧接着给oldfd打开了一个
文件foodup2,再调用dup2将oldfd复制到newfd,往newfd写入“hello 123\n”。查看结果: cat foodup2
上面例子编译后,在我的电脑上执行:
[root@localhost unix]# ./a.out
oldfd: 3
newfd: 4
write ok
newfd: 3
return ret: 8, oldfd:8
dup兄弟俩存在的意义?
dup兄弟俩的用法是弄清楚了,但是他们到底有什么用,像这样来复制文件描述符不是浪费表情吗?
其实不然,在某些时候,我们要重定向一个FD,例如想把标准输出重定向到一个文件里,dup就可以把STDOUT_FILENO这个值断开与屏幕输出的联系,转而勾搭上某个文件的FD。或者STDIN_FILENO默认是标准输入,当dup2(oldfd, STDIN_FILENO)时候,输入则成了oldfd所对应的文件。尤其是在涉及到管道编程的时候尤其有用。另外一方面,新旧FD共享文件偏移和状态,在多线程编程的时候,可以更好的同步数据。