【问题标题】:Can someone explain what dup() in C does?有人可以解释 C 中的 dup() 做什么吗?
【发布时间】:2011-12-13 06:43:44
【问题描述】:

我知道 dup, dup2, dup3 "创建文件描述符 oldfd 的副本"(来自手册页)。但是我无法消化它。

据我所知,文件描述符只是数字,用于跟踪文件位置及其方向(输入/输出)。这样做不是更容易吗

fd=fd2;

每当我们想要复制文件描述符时?

还有别的……

dup() 使用编号最小的未使用描述符作为新描述符。

这是否意味着如果我们假设我们有 close( )-ed 其中之一?

【问题讨论】:

  • 对于第一个问题,您需要记住内核会跟踪打开文件句柄的数量。 dup 是您告诉内核您希望它跟踪另一个文件句柄(指同一个文件)的方式,直到您 close 它。

标签: c pipe dup2 dup


【解决方案1】:

dup() 和 dup2() 系统调用

•dup() 系统调用复制打开的文件描述符并返回新文件 描述符。

•新文件描述符具有以下共同属性 原本的 文件描述符: 1.指同一个打开的文件或管道。 2. 具有相同的文件指针——即两个文件描述符共享一个文件指针。 3. 具有相同的访问模式,无论是读、写还是读写。

• dup() 保证返回具有最低可用整数值的文件描述符。正是由于这个返回可用的最低未使用文件描述符的特性,进程完成了 I/O 重定向。

int dup(file_descriptor)

int dup2(file_descriptor1, file_descriptor2)

【讨论】:

    【解决方案2】:

    例子:

    close(1);     //closing stdout
    newfd=dup(1); //newfd takes value of least available fd number
    

    文件描述符发生这种情况的地方:

    0 stdin     .--------------.     0 stdin     .--------------.     0 stdin
    1 stdout   =|   close(1)   :=>   2 stderr   =| newfd=dup(1) :=>   1 newfd
    2 stderr    '--------------'                 '--------------'     2 stderr
    

    又出现了一个问题:我怎样才能dup()一个我已经关闭的文件描述符?

    我怀疑您是否使用显示的结果进行了上述实验,因为那不符合标准 - 参见。 dup:

    如果出现以下情况,dup() 函数将失败:

    [EBADF]
    fildes 参数不是有效的打开文件描述符。

    所以,在显示的代码序列之后,newfd 一定不是1,而是-1errno EBADF

    【讨论】:

      【解决方案3】:

      只是关于“复制标准输出”的提示。

      在某些 Unix 系统上(但不是 GNU/Linux)

      fd = open("/dev/fd/1", O_WRONLY);
      

      相当于:

      fd = dup(1);
      

      【讨论】:

        【解决方案4】:

        只是想在尝试了一下之后就第二个问题回答自己。

        答案是是的。如果 stdin、stdout 或 stderr 关闭,您创建的文件描述符可以取值 0、1、2。

        例子:

        close(1);     //closing stdout
        newfd=dup(1); //newfd takes value of least available fd number
        

        文件描述符发生这种情况的地方:

        0 stdin     .--------------.     0 stdin     .--------------.     0 stdin
        1 stdout   =|   close(1)   :=>   2 stderr   =| newfd=dup(1) :=>   1 newfd
        2 stderr    '--------------'                 '--------------'     2 stderr
        

        【讨论】:

        • 又出现了一个问题:我怎样才能dup()一个我已经关闭的文件描述符?
        • 根据定义,dup() 使用编号最小的未使用描述符作为新描述符。而当你关闭一个文件描述符时,这意味着它可以被使用。
        【解决方案5】:

        dup() 最重要的一点是它返回可用于新文件描述符的最小整数。这就是重定向的基础:

        int fd_redirect_to = open("file", O_CREAT);
        close(1); /* stdout */
        int fd_to_redirect = dup(fd_redirect_to); /* magically returns 1: stdout */
        close(fd_redirect_to); /* we don't need this */
        

        在写入文件描述符 1 (stdout) 之后,会神奇地进入“文件”。

        【讨论】:

        • 假设(并非不合理)文件描述符 0 当前处于打开状态。如果没有dup2()(或dup3(),但这是系统最近添加的),对200>somefile 等重定向的支持非常不方便。
        【解决方案6】:

        文件描述符不仅仅是一个数字。它还带有各种半隐藏状态(是否打开,它引用的文件描述以及一些标志)。 dup 复制此信息,因此您可以例如分别关闭两个描述符。 fd=fd2 没有。

        【讨论】:

        • 这个。 “数字”是内核维护的数据结构的索引。 dup 系列函数克隆该数据结构中节点的状态,并将索引交给新节点。
        • @dmckee:“内核”和“索引”是实现细节。有一些与“数字”相关的数据,程序无法直接操作,被dup()克隆。这就是程序员需要知道的一切。顺便说一句,它不是一个非常有趣的数据,它只是几个标志和一个真正有趣的数据(打开的文件描述)的索引,它不是dup() 克隆的。
        【解决方案7】:

        假设您正在编写一个 shell 程序,并且您想要在您想要运行的程序中重定向标准输入和标准输出。它可能看起来像这样:

        fdin = open(infile, O_RDONLY);
        fdout = open(outfile, O_WRONLY);
        // Check for errors, send messages to stdout.
        ...
        int pid = fork(0);
        if(pid == 0) {
            close(0);
            dup(fdin);
            close(fdin);
            close(1);
            dup(fdout);
            close(fdout);
            execvp(program, argv);
        }
        // Parent process cleans up, maybe waits for child.
        ...
        

        dup2() 是一种更方便的方法,close() dup() 可以替换为:

        dup2(fdin, 0);
        dup2(fdout, 1);
        

        你想这样做的原因是你想向stdout(或stderr)报告错误,所以你不能只是关闭它们并在子进程中打开一个新文件。其次,如果任何一个 open() 调用都返回错误,那么进行 fork 将是一种浪费。

        【讨论】:

          【解决方案8】:

          看到这个page,stdout可以别名为dup(1)...

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-04-18
            • 2018-04-26
            • 2019-12-16
            • 1970-01-01
            • 2021-04-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多