dup linux C

#include<unistd.h>

  int dup(int fd);

  int dup2(int fd1,int fd2);
  两个均为 复制一个现存 的文件的描述
  两个函数的返回:若成功为新的文件描述,若出错为-1;

  由dup返回的新文件描述符一定是当前可用文件描述中的最小数值。用dup2则可以用fd2参数指定新的描述符数值。如果fd2已经打开,则先关闭。若fd1=fd2,则dup2返

回fd2,而不关闭它。通常使用这两个系统调用来重定向一个打开的文件描述符。


函数简介

  函数名:  dup
  功 能: 复制一个文件句柄
  用 法: int   dup(int handle);
  相关函数: dup2、fdopen、freopen、mbsdup、wcsdup、strdup

  1. #include <string.h>  
  2. #include <stdio.h>  
  3.   
  4. void flush(FILE *stream);  
  5.   
  6. int main(void)  
  7. {  
  8.     FILE    *fp;  
  9.     char    msg[] = "This is a test";  
  10.       
  11.     /*create a file*/  
  12.     fp = fopen("DUMMY.FIL","w");  
  13.       
  14.     /*write some date to the file*/  
  15.     fwrite(msg,strlen(msg),1,fp);  
  16.     printf("Press any key to flush DUMMY.FIL");  
  17.     getchar();  
  18.   
  19.     /*flush the data to DUMMY.FIL without closing it*/  
  20.     flush(fp);  
  21.     printf("\n File was flushed,Press any key to quit:");  
  22.     getchar();  
  23.     return 0;  
  24. }  
  25.   
  26. void flush(FILE *stream)  
  27. {  
  28.     int duphandle;  
  29.   
  30.     /*flush TC's internal buffer*/  
  31.     fflush(stream);  
  32.       
  33.     /* make a duplicate file handle*/  
  34.     duphandle = dup(fileno(stream));  
  35.     /* close the duplicate handle to flush the DOS buffer*/  
  36.     close(DUPHANDle);  
  37. }  


一、单个进程内的dup和dup2

假设进程A拥有一个已打开的文件描述符fd3,它的状态如下
进程A的文件描述符表(before dup2)

[plain]  view plain copy print ?
  1.    ------------  
  2. fd0 0   | p0  
  3.    ------------  
  4. fd1 1   | p1 -------------> 文件表1 ---------> vnode1  
  5.    ------------  
  6. fd2 2   | p2  
  7.    ------------  
  8. fd3 3   | p3 -------------> 文件表2 ---------> vnode2  
  9.    ------------  
  10. ... ...  
  11. ... ...  
  12.    ------------  

经下面调用:
n_fd = dup2(fd3, STDOUT_FILENO);后进程状态如下:
进程A的文件描述符表(after dup2)
[plain]  view plain copy print ?
  1.    ------------  
  2. fd0 0   | p0  
  3.    ------------  
  4. n_fd 1   | p1 ------------  
  5.    ------------               \  
  6. fd2 2   | p2                  \  
  7.    ------------                 _\|  
  8. fd3 3   | p3 -------------> 文件表2 ---------> vnode2  
  9.    ------------  
  10. ... ...  
  11. ... ...  
  12.    ------------  

解释如下:n_fd = dup2(fd3, STDOUT_FILENO)表示n_fd与fd3共享一个文件表项(它们的文件表指针指向同一个文件表项),n_fd在文件描述符表中的位置为 STDOUT_FILENO的位置,而原先的STDOUT_FILENO所指向的文件表项被关闭,我觉得上图应该很清晰的反映出这点。按照上面的解释我们就可以解释CU中提出的一些问题:
(1) "dup2的第一个参数是不是必须为已打开的合法filedes?" -- 答案:必须。
(2) "dup2的第二个参数可以是任意合法范围的filedes值么?" -- 答案:可以,在Unix其取值区间为[0,255]。

(每一个进程都对应一个结构体  task_struct ,里面包含一个数据成员 :

  1. /* open file information */  
  2.         struct files_struct *files;  


files_struct 结构体定义如下:

  1. /* 
  2.  * Open file table structure 
  3.  */  
  4. struct files_struct {  
  5.   /* 
  6.    * read mostly part 
  7.    */    
  8.         atomic_t count;  
  9.         struct fdtable __rcu *fdt;  
  10.         struct fdtable fdtab;  
  11.   /* 
  12.    * written part on a separate cache line in SMP 
  13.    */    
  14.         spinlock_t file_lock ____cacheline_aligned_in_smp;  
  15.         int next_fd;  
  16.         struct embedded_fd_set close_on_exec_init;  
  17.         struct embedded_fd_set open_fds_init;  
  18.         struct file __rcu * fd_array[NR_OPEN_DEFAULT];  
  19. };  
 对于上面的两个句柄 n_fd  fd3 他们在 files_struct 里面的数组 fd_array 里面对应的数值 是相等的。



二、重定向后恢复
CU上有这样一个帖子,就是如何在重定向后再恢复原来的状态?首先大家都能想到要保存重定向前的文件描述符。那么如何来保存呢,象下面这样行么?
int s_fd = STDOUT_FILENO;
int n_fd = dup2(fd3, STDOUT_FILENO);
还是这样可以呢?
int s_fd = dup(STDOUT_FILENO);
int n_fd = dup2(fd3, STDOUT_FILENO);
这两种方法的区别到底在哪呢?答案是第二种方案才是正确的,分析如下:按照第一种方法,我们仅仅在"表面上"保存了相当于fd_t(按照我前面说的理解方法)中的index,

而在调用dup2之后,ptr所指向的文件表项由于计数值已为零而被关闭了,我们如果再调用dup2(s_fd, fd3)  (注意此时s_fd对应的文件表项已经关闭)就会出错。而第二种方法我们首先做一下复制(这样对应的文件表项不会被关闭),复制后的状态如下图所示:
进程A的文件描述符表(after dup)

[plain]  view plain copy print ?
  1.    ------------  
  2. fd0 0   | p0  
  3.    ------------  
  4. fd1 1   | p1 -------------> 文件表1 ---------> vnode1  
  5.    ------------                 /|  
  6. fd2 2   | p2                /  
  7.    ------------             /  
  8. fd3 3   | p3 -------------> 文件表2 ---------> vnode2  
  9.    ------------          /  
  10. s_fd 4   | p4 ------/  
  11.    ------------  
  12. ... ...  
  13. ... ...  
  14.    ------------  
调用dup2后状态为:
进程A的文件描述符表(after dup2)
[plain]  view plain copy print ?
  1.    ------------  
  2. fd0 0   | p0  
  3.    ------------  
  4. n_fd 1   | p1 ------------  
  5.    ------------               \  
  6. fd2 2   | p2                 \  
  7.    ------------                _\|  
  8. fd3 3   | p3 -------------> 文件表2 ---------> vnode2  
  9.    ------------  
  10. s_fd 4   | p4 ------------->文件表1 ---------> vnode1  
  11.    ------------  
  12. ... ...  
  13. ... ...  
  14.    ------------  

dup(fd)的语意是返回的新的文件描述符与fd共享一个文件表项。就如after dup图中的s_fd和fd1共享文件表1一样。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值