2013-03-28 67 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()會分配兩個描述符的(注意,當創建一個管道時,管道兩端使用的文件描述符是下一個編號最小的描述符),因此檢查將變得有意義。