c - dup2 参数顺序困惑

标签 c linux system-calls dup2

我写了这个简单的程序:

#include<stdio.h>
#include<unistd.h>
#include <fcntl.h> 
#include <stdlib.h>
int main(){
    int fd = open("theFile.txt", O_CREAT | O_RDWR, 0666);
    if(fd<0){
     printf("coudlnt open File descriptor \n"); 
    }   
    pid_t pid = fork();
    if(pid==0){
        dup2(int oldFD, int newFD);
    dup2(fd,1);
        execlp("/bin/ls","ls","-l", NULL);      
    }
    return 0;
}

我想要的是将 ls - l 的输出重定向到名为“theFile.txt”的文件。该代码按我的预期工作。这里让我困惑的是 dup2 参数的顺序。我相信正确的顺序应该是 dup2(1, fd) - 将 fd 视为 newFD 并将 1 视为oldFD。但是当我将它用作 dup2(fd,1) 时,代码可以工作,根据 SO 上的一些其他答案,它基本上是 fd 的标准输出。

这里的oldFD fd怎么样,这里的newFD1怎么样?如果1newFD,为什么这个程序首先可以工作?

此外,在我调用 dup2 后,execlp 会覆盖子进程的地址空间。 dup2 如何连接到 execlp 以获得所需的结果。即我所做的 cat theFile.txt 我得到了当前直接列出的内容。

我可以在这里得到一些解释吗?

最佳答案

根据[man7]: DUP(2) :

int dup2(int oldfd, int newfd);

...

The dup() system call creates a copy of the file descriptor oldfd,
using the lowest-numbered unused file descriptor for the new
descriptor.

...

The dup2() system call performs the same task as dup(), but instead
of using the lowest-numbered unused file descriptor, it uses the file
descriptor number specified in newfd. If the file descriptor newfd
was previously open, it is silently closed before being reused.

将数据(例如文本)输出到控制台时,应用程序使用 stdout 流(也stderr,但为了简单起见,我们将其忽略)。 stdoutfileno1 (最好使用常量而不是值,因为值可能会改变 - 在 this 中不太可能 情况,但一般而言):

cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q048923791$ cat /usr/include/unistd.h | grep STDOUT
#define   STDOUT_FILENO   1   /* Standard output.  */

在您的子进程中,ls(通过execlp)将其数据吐出到stdout(文件号1) 。 在此之前,将进行dup2调用。当前情况,dup2调用之前(为了清楚起见,我将在引用stdout时使用定义的宏>文件号):

  • fd:指向自定义文件(之前打开过)
  • STDOUT_FILENO:指向stdout

dup2 调用:

  1. dup2(fd, STDOUT_FILENO)(就像现在一样):关闭当前的STDOUT_FILENO并将fd复制到 STDOUT_FILENO。目前情况:

    • fd:指向自定义文件
    • STDOUT_FILENO:指向自定义文件
  2. dup2(STDOUT_FILENO, fd):关闭当前fd并将STDOUT_FILENO复制到fd。目前情况:

    • fd:指向stdout
    • STDOUT_FILENO:指向stdout

正如所见,对于#1.,当数据输出到stdout时,它实际上会转到自定义文件(与#2相反) . 它将转到 stdout,即使使用 fd)。

关于第二问题:

  • [man7]: EXEC(3) :

    The exec() family of functions replaces the current process image
    with a new process image. The functions described in this manual
    page are front-ends for execve(2).

  • [man7]: EXECVE(2) :

    By default, file descriptors remain open across an execve().

    ...

    POSIX.1 says that if file descriptors 0, 1, and 2 would
    otherwise be closed after a successful execve(), and the process
    would gain privilege because the set-user-ID or set-group_ID mode
    bit was set on the executed file, then the system may open an
    unspecified file for each of these file descriptors. As a general
    principle, no portable program, whether privileged or not, can
    assume that these three file descriptors will remain closed across
    an execve().

文件描述符将从子进程传递到ls


以下是代码 (code00.c) 的改进版本(仅进行了细微更改):

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>


int main() {
    int ret = 0, fd = open("thefile.txt", O_CREAT | O_RDWR, 0666);
    if (fd < 0) {
        printf("Coudln't open file: %d\n", errno);
        ret = 1;
    }
    pid_t pid = fork();
    if (pid == 0) {
        // dup2(int oldFD, int newFD);
        if (dup2(fd, STDOUT_FILENO) < 0) {
            printf("Couldn't redirect stdout: %d\n", errno);
            ret = 2;
        }
        execlp("/bin/ls", "ls", "-l", NULL);
    } else if (pid < 0) {
        printf("Couldn't spawn child process: %d\n", errno);
        ret = 3;
    }
    return ret;
}

关于c - dup2 参数顺序困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48923791/

相关文章:

ruby-on-rails - Ruby 守护进程不会在系统启动时执行

c++ - 强制读取系统调用阻塞

C uint16 整数或字符格式?

c - C中的函数名是什么类型?

c - 错误 C4996 : visual studio: why do I get an error when I use fopen in c?

c - Unix 中的 'whiteout' (S_IFWHT) 是什么?

operating-system - 在虚拟机中如何处理系统调用?

c - 链接列表创建 - 程序在接受输入后停止工作

c - 两次调用 mmap 时出现 SIGSEGV

linux - 在 Fedora 中安装虚拟 PC