C/400

78. pipe と標準入出力について(3)

pipe の機能の発揮を見てもらう前に簡単な pipe による標準入出力の結合を紹介しよう。
次の例は同一プロセス内での標準出力( STDOUT ) を標準入力( STDIN ) にリダイレクトさせる例である。

-------------------------------------------------------------------------------
0001.00 #include <stdio.h>                                               
0002.00 #include <stdlib.h>                                              
0003.00 #include <string.h>                                              
0004.00 #include <unistd.h>                                              
0005.00                                                                     
0006.00 #define TRUE         0                                              
0007.00 #define FALSE       -1                                              
0008.00                                                                     
0009.00 void main(void){                                                    
0010.00   int  fildes[2];                                                   
0011.00   int  rc, bytesWritten, bytesRead;                                 
0012.00   char writeData[10], readData[11];                                 
0013.00                                                                     
0014.00   printf("** TESTPIPE: PIPE のテスト ***\n");                       
0015.00   getchar();                                                        
0016.00                                                                     
0017.00   memset(writeData, 'A', 10);                                       
0018.00                                                                     
0019.00   /*(1) fildes[0] と fildes[1] を pipe で結ぶ */                    
0020.00   pipe(fildes);                                                     
0021.00                                                                     
0022.00   /*(2) fildes[1] に文字列 writeData を出力する */                  
0023.00   if((bytesWritten = write(fildes[1], writeData, 10)) == FALSE){    
0024.00     perror("write error");                                          
0025.00   }                                                                 
0026.00   else{/* 成功 */                                                   
0027.00     printf("wrote %d bytes\n", bytesWritten);                       
0028.00     /*(3) fildes[0] から文字列  readData を読み取る */              
0029.00     if((bytesRead = read(fildes[0], readData, 10)) == FALSE){       
0030.00       perror("read error");                                         
0031.00     }                                                               
0032.00     else{/* 読取り成功 */                                           
0033.00       /*(4) fildes[0] からの読み取り結果を表示する */               
0034.00       printf("read %d bytes\n", bytesRead);                         
0035.00       readData[10] = 0x00;                                          
0036.00       printf("readData is [%s]\n", readData);                       
0037.00     }/* 読取り成功 */                                               
0038.00   }/* 成功 */                                                       
0039.00   close(fildes[0]);                                                 
0040.00   close(fildes[1]);                                                 
0041.00                                                                     
0042.00   getchar();                                                        
0043.00 }                                                                   
-------------------------------------------------------------------------------

実行すると次のような結果が表示される。

実行画面

【解説】

最初に 0010.00 int fildes[2]; によって 2項目のファイル識別子のセットを用意しておく。
次に、

  0019.00   /*(1) fildes[0] と fildes[1] を pipe で結ぶ*/ 
  0020.00   pipe(fildes);

によって filedes[0]fildes[1] を pipe で結ぶ。
詳しく説明すると pipe という関数(命令) は 2つの新しいファイル識別子を生成すると同時に
それら2つをリダイレクトして結合するのである。
つまり pipe は既存の 1組のファイル識別子を結合するのではなく、新たに空き番号のある
ファイル識別子を新規に作成して、それらを結合させるのである。
例えばファイル識別子は 1番はすでに使われていて 0 番と 2 番が空いているのであれば
pipe によって fildes[0] は 0 番、 fildes[1] は 2 番として割り振られます。
上記のサンプルの場合は初めて実行されるのだから、

  fildes[0] = 0,  fildes[1] = 1

となるだろう。
次に、

  0023.00   if((bytesWritten = write(fildes[1], writeData, 10)) == FALSE){

によってAAA... が保管されている変数 writeData の 10バイトを fildes[1] に出力しておいてから

  0029.00     if((bytesRead = read(fildes[0], readData, 10)) == FALSE){

によって fildes[0] を読み取ると readData には 先の AA ... の文字列が入ります。
つまり fildes[1] に書き込まれた AAA ... という文字列は fildes[0] を通じて
読み取られたことになる。

pipe 関数は結合された1組のファイル識別子を新しく生成する。

という基本を抑えておいて頂きたい。