linux系统调用dup,dup2,dup3

本文翻译自Ubuntu的Linux Programmer's Manual,详细介绍了dup、dup2和dup3这三个用于复制文件描述符的系统调用。dup()创建oldfd的副本,而dup2()允许指定newfd作为新描述符。dup3()增加了设置close-on-exec标志的选项,并在oldfd等于newfd时返回错误。成功返回新文件描述符,失败则返回-1并设置errno。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

翻译自Ubuntu下的Linux Programmer's Manual

名字:

dup,dup2,dup3-复制一个文件描述府。

摘要:

#include<unistd.h>

int dup(int oldfd);
int dup2(int oldfd,int newfd);
#define _GNU_SOURCE  /*见 feature_test_macros(7) */
#include<fcntl.h>    /* 获取 O_*的常量定义 */
#include<unistd.h>
int dup3(int oldfd,int newfd,int flags);

描述:

        dup()系统调用生成文件描述府oldfd的一个副本,从未使用的文件描述符当中选取最小的文件描述符作为新的文件描述符。

        当成功返回后,旧的文件描述符和新的文件描述符可以互换使用,这两个描述符指向了同一个打开的文件描述(见系统调用open()),他们共享同一个文件偏移量和文件状态标志。比如说,当使用lseek操作某一个文件描述符,改变了该文件的偏移量的时候,使用另外一个描述符看到的是相同的偏移量。

        这两个描述符不会共享文件描述符标志(例如 close-on-exec标志)。如果旧的文件描述符有close-on-exec标志,则新的文件描述符没有。

        dup2()

        dup2()系统调用完成和dup相同的功能。但是dup2并不将未使用的文件描述符的最小值作为新的文件描述符,它使用参数newfd作为新的文件描述符。如果newfd在之前已经打开了,会先将打开的文件关闭,在完成文件描述符的复制操作。

        关闭newfd之前打开的文件和复制newfd新的文件描述符这个操作是原子的。这个操作的原子性至关重要,因为实现close()和dup()两个函数相同的功能涉及到竞争问题。也就是说在关闭了newfd打开的文件之后,将newfd复制为新的文件描述符之前,newfd有可能已经被重新定义成其他文件的文件描述符了。这种情况有可能会发生,比如说主程序被一个信号打断,或者在完成了close操作之后,又有一个并行执行的线程分配了这个文件描述符。

        注意一下要点:

        *  如果oldfd不是一个有效的文件描述符,此次调用失败,newfd打开的文件也不关闭

        * 如果oldfd是一个有效的文件描述符,并且newfd=oldfd,dup2什么也不做,直接返回newfd()

        dup3()

        dup3实现和dup2相同的功能,但有以下差别:

        *  调用这可以设定close-on-exec标志,这个操作可以通过指定flags参数里面的O_CLOEXEC。参考open系统调用里面相同的标志参数,那里面解释了为什么这样做是有效的。

        * 如果oldfd等于newfd,dup3调用失败,伴随这一个错误EINVAL。

返回值:

        如果调用成功,返回新的文件描述符。调用失败,返回-1并且errno被设定为适当的值

 

错误(errorno):

        EBADF :oldfd不是一个打开文件的描述符。

        EBADF :newfd超出了文件描述符的范围。

        EBUSY:(只有linux平台下有) 当出现多线程资源竞争的时候,dup2或dup3会返回。

        EINTR: dup2或者dup3被一个信号打断。

        EINVAL:dup3的flags参数是一个无效值

        EINVAL:dup3的oldfd等于newfd。

        EMFILE:该进程打开文件的文件描述符的数量达到了上限。

版本:

        dup3加入了linux 2.6.27版本,从2.9版本开始支持glibc

遵守规则:(这个好像并没什么卵用,但是因为强迫症的缘故还是想完整翻出来)

        dup,dup2:POSIX.1-2001,POSIX.1-2008,SVr4,4.3BSD

        dup3是linux特有的

注意:

        当newfd超过了文件描述符规定的范围的时候,dup2()的返回值和funtl(... , F_DUPFD, ...)的返回值不同。在某些操作系统上,dup2也会想F_DUPFD一样返回EINVAL。

        如果newfd是一个已经打开的文件,执行dup2的时候,在关闭newfd原来打开的文件的时候,如果这个时候出错,那么这些错误就都会被忽略。考虑到这种情况,除非你的程序是单线程的,并且在信号处理程序中不会分配文件描述符,否则不要在调用dup2之前调用close,因为多线程情况下存在资源竞争(译者注:如果先调用close(newfd)在调用dup2(oldfd,newfd)有可能在两步调用操作之间有另外一个线程首先给newfd分配了文件,从而产生错误。)我们可以使用以下的代码:

/* 获取一个newfd的副本,这样可以在接下来的过程中检查close中出现的错误,EBADF错误表示
newfd没有打开 */

           tmpfd = dup(newfd);
           if (tmpfd == -1 && errno != EBADF) {
               /* 处理复制过程中的错误 */
           }

           /* 原子操作,复制 */

           if (dup2(oldfd, newfd) == -1) {
               /* Handle dup2() error */
           }

           /* 可以通过检查tmpfd来判断在关闭newfd的时候是否产生了错误 */

           if (tmpfd != -1) {
               if (close(tmpfd) == -1) {
                   /* Handle errors from close */
               }
           }

其他:

        close(2),fcntl(2),open(2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值