2013-03-28 56 views
0

有人可以请解释使用dup2之后检查fd [0]!= STDIN_FILENO,因为从我了解fd [0]!= STDIN_FILENO将失败,dup2仍然会返回除STDIN_FILENO以外的东西,只是试图了解一些示例代码,谢谢,如果有人可以解释为什么使用excelp这将是一个很大的问题。dup2后fd [0]!= STDIN_FILENO

int fd[2]; 
pid_t pid; 

if(argc != 2) { 
     fprintf(stderr, "Must be specify exactly 1 file\n"); 
     exit(0); 
    } 

    if(pipe(fd) < 0) 
     exit(1);./ 

    pid = fork(); 

    switch (pid) { 
     case -1: 
      exit(1); 
     case 0: 
      close(fd[1]); 
         //here 
      if(fd[0] != STDIN_FILENO) { 
       if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) 
        exit(3); 
       close(fd[0]); 
      } 
      if(execlp("tr", "tr", "[a-z]", "[A-Z]", (char *) 0) < 0) 
       exit(4); 
      break; 

     default: 
      close(fd[0]); 
         // and here 
      if(fd[1] != STDIN_FILENO) { 
       if(dup2(fd[1], STDIN_FILENO) != STDIN_FILENO) 
        exit(5); 
       close(fd[1]); 
      } 
      if(execlp("cat", "cat", argv[1], (char *) 0) < 0) 
       exit(4); 
      break; 
    } 
    return 0; 
+0

有没有人理解为什么代码使用* unidirectional *管道的* write * end作为* stdin *?此代码看起来不正确。 – thejh 2013-03-28 09:15:30

+0

谢谢大家!!!!! – cincybengal 2013-03-28 09:24:00

+1

@thejh是的,默认(父母)的情况是错误的...那些应该是STDOUT_FILENO – 2013-03-28 09:24:03

回答

2

其目的是使stdin(STDIN_FILENO,它是0)指向fd [0]指向的文件(管道的读取端)。首先检查它们是否已经不相同......如果是,代码会将0重复为0,然后关闭0 - 不好。如果它们不相同,则使用dup2使fD [0]指向的STDIN_FILENO点。如果dup2成功,它将返回第二个参数,所以如果dup2失败,那么检查就会被调用退出。

你写

据我了解FD [0]!= STDIN_FILENO会失败

它不完全清楚为什么你 “理解” 这一点。只有当fd [0]包含STDIN_FILENO(即0)时它才会失败,但由于它包含由pipe调用分配的文件描述符,所以它不太可能。

DUP2仍然会返回其他的东西比STDIN_FILENO

如果成功DUP2返回第二个参数。它不会返回除STDIN_FILENO以外的东西,除非它失败 - 为什么会这样? - 在这种情况下,它返回-1。

+0

这使得总体感谢你,如果你不介意,你可以解释exclep,因为我可以理解你的解释。谢谢。 – cincybengal 2013-03-28 09:11:03

+0

@cincybengal execlp的第一个参数是要运行的程序的文件名(路径)。其余参数是程序的命令行参数,第一个参数通常是程序的名称 - 这就是为什么有两个“tr”,一个是程序路径,另一个是程序名。如果你想知道tr做什么以及如何解释它的论点,请阅读它的手册页。 – 2013-03-28 09:17:35

+0

所以它只是执行tr程序,并使用其余的命令行参数,而不是null它的(char *)0,感谢您的耐心,当我无法理解代码时,它使我疯狂。 – cincybengal 2013-03-28 09:23:43

0

该程序将运行在父进程的猫,并在子进程运行TR,并希望通过TR读取猫的输出。

在开始时,它会打开一个管道,父节点将写入fd [1],并且子节点将从fd [0]读取,以便父节点可以将数据写入子节点。

在父项中,它将dup fd [1]复制到stdin;并在孩子它dup fd [0]到标准输入。

在child中,execlp运行tr,tr将从标准输入读取,并且由于标准输入已经被重复为fd [0],所以它实际上读取管道中的输出。

execlp()在当前进程中运行一个新的可执行文件。你可能会在man execlp的参数细节。

+0

但为什么是dup2调用必要的,并且在孩子中不应该调用dup,除非fd [1]没有被正确初始化,我man paged execlp,我仍然不知道究竟发生了什么,但感谢您的帮助 – cincybengal 2013-03-28 09:02:44

+0

为什么dup2是必要的?因为stdin是0,tr只知道stdin,它没有实现fd [0]。所以它必须将fd [0]复制到stdin。 – TieDad 2013-03-28 09:06:35

1

execlp基本上执行程序。该程序将从STDIN_FILENO(换句话说,fd 0)读取其输入。系统调用dup2close用于将fd[0]fd[1]文件描述符移动到该编号。

+0

所以你的说法是,当f [0]在父项中关闭时,dup2将在子项中启动,然后excelp将在父项中执行?对不起,如果这是微不足道的,但为什么(char *)0 – cincybengal 2013-03-28 09:07:47

+0

@cincybengal阅读我链接到的execlp manmage。这里使用'(char *)0'来代替'NULL'来终止参数列表。总体感觉是 – thejh 2013-03-28 09:11:27

+0

谢谢。 – cincybengal 2013-03-28 09:13:22

1

fd[0] != STDIN_FILENO的检查是一个防御性的编程实践,因为通常的标准输入和标准输出先前已被打开,但如果他们这样做了pipe()调用之前都被关闭,pipe()会分配两个描述符的(注意,当创建一个管道时,管道两端使用的文件描述符是下一个编号最小的描述符),因此检查将变得有意义。