dup和dup2函数

1. 文件描述符在内核中数据结构

    在具体说dup/dup2之前, 我认为有必要先了解一下文件描述符在内核中的形态。

一个进程在此存在期间,会有一些文件被打开,从而会返回一些文件描述符,从shell

中运行一个进程,默认会有3个文件描述符存在(0、1、2), 0与进程的标准输入相关联,

1与进程的标准输出相关联,2与进程的标准错误输出相关联,一个进程当前有哪些打开

的文件描述符可以通过/proc/进程ID/fd目录查看。 下图可以清楚的说明问题:


  进程表项
――――――――――――――――

   fd标志 文件指针
      _____________________
fd 0:|________|____________|------------> 文件表
fd 1:|________|____________|
fd 2:|________|____________|
fd 3:|________|____________|
     |      .......          |
     |_____________________|

                图1

文件表中包含:文件状态标志、当前文件偏移量、v节点指针,这些不是本文讨论的

重点,我们只需要知道每个打开的文件描述符(fd标志)在进程表中都有自己的文件表

项,由文件指针指向。

2. dup/dup2函数

APUE和man文档都用一句话简明的说出了这两个函数的作用:复制一个现存的文件描述符。

#include <unistd.h>

int dup(int oldfd);

int dup2(int oldfd, int newfd);

从图1来分析这个过程,当调用dup函数时,内核在进程中创建一个新的文件描述符,此

描述符是当前可用文件描述符的最小数值,这个文件描述符指向oldfd所拥有的文件表项。


  进程表项
――――――――――――――――

   fd标志 文件指针
      _____________________
fd 0:|________|____________|                    ______
fd 1:|________|____________|----------------> |       |
fd 2:|________|____________|                   |文件表|
fd 3:|________|____________|----------------> |______|
     |      .......          |
     |_____________________|

                图2:调用dup后的示意图

如图2 所示,假如oldfd的值为1, 当前文件描述符的最小值为3, 那么新描述符3指向

描述符1所拥有的文件表项。

dup2和dup的区别就是可以用newfd参数指定新描述符的数值,如果newfd已经打开,则

先将其关闭。如果newfd等于oldfd,则dup2返回newfd, 而不关闭它。dup2函数返回的新

文件描述符同样与参数oldfd共享同一文件表项。

APUE用另外一个种方法说明了这个问题:

实际上,调用dup(oldfd);

等效与
        fcntl(oldfd, F_DUPFD, 0)

而调用dup2(oldfd, newfd);

等效与
        close(oldfd);
        fcntl(oldfd, F_DUPFD, newfd);

printf -> stdout -> STDOUT_FILENO(1) -> 终端(tty)

重拾终端输出方法

ttyfd = open("/dev/tty", O_RDWR);

dup2(ttyfd, STDOUT_FILENO);

close(ttyfd);


你可能感兴趣的:(dup)