ファイル - みる会図書館


検索対象: 月刊 C MAGAZINE 1990年10月号
75件見つかりました。

1. 月刊 C MAGAZINE 1990年10月号

ライフホート 0 「 m on from (ompiler ma 「 5 [ a i00 C ださい 先月号に続き , LatticeC のユー ティリティの使い方の説明をしま す。 となります。 ます。 lmk が終了すると , 環境変数 は lmk 実行前の元の状態に戻りま ( 7 ) オプション文 ( 制御文 ) ( 5 ) 継続行 す。 TabIe 2 に挙げた 6 個のオプショ クのうしろて、改行すると , 次 ②ー mk.exe. 9touch. exe ン文が使えます。とくに , SET 文 行に継続となります。行末を \ ク て終わりたいときは , \ \ とふたっ は , 環境変数 include などを一時的 重ねます。設定方法の例としては , に変更てきますから , いろいろな ( 3 ) マクロ SYNOPSIS コンパイラを使う人は , 各コンパ 付録ディスク LIST2 を参照してく 行の先頭て、 symbol = literal のよ touch file うに定義てき , $(symbaol) て呼び イラに合わせて , make ファイルを ださい lmk の補助ューティリティてす。 作っておくと有用て、しよう。 出せます。 lmk のコマンドラインか file のタイムスタンプを , システム ( 6 ) インライン応答ファイル . DEFAULT : と . ONERROR : らも設定てき , コマンドラインの の時刻 ( 通常 , 現在の時刻 ) にしま の後には , 1 行以上のコマンドが続 link や lmb のよう・に , ファイルか ほうが優先されます。デフォルト す。たとえば , ソースファイルは かなければなりません。設定方法 らコマンド入力の行えるものは , <Table 1 のようなマクロが定義さ 更新していませんが , make ファイ の例としては付録ディスク LIST4 コマンドファイルを make ファイル れています。設定方法の例として ルて、コンパイルオプションを変更 の中に記述て、きます。コマンドラ を参照してください は , 付録ディスク LISTI を参照して したのて , 再コンパイルしたいと イン上て , 入力ファイル名を指定 このときカレントディレクトリ ください。これは ,lc-cus-gs-k2 , touch コマンドを使い , ソー , stdio. h がなければ , lmk は するところにヾく @ < 〃と記述し , -i*targetYsYsamp. Obj samp. c と スファイルのタイムスタンプを更 lmkfile に指定されている c:Ylc に 次の行から , 行の先頭がヾく〃の 展開されます。 新し lmk を起動します。 行まてをコマンドファイルとして 捜しにいきます。コンパイラは , include に指定されている c : Ylc 扱います。設定方法の例としては , ( 4 ) コメント に , ヘッダファイルを捜しにいき # 記号から行末まてが , コメント 付録ディスク LIST3 を参照してく lc コマンド C-Dn(n=0, 1 , 2 , TabIe 1 ー mk デフォルト定義マクロ 3 , 4 ) をつけると , . exe ファイルに デバッグ情報が書き込まれます。 拡張子なしの先頭のソースファイル名 lstrip コマンドは , そのデバッグ情 ターゲットファイル名 報を削除するユーティリティてす。 、 $ く バス名なしの先頭のソースファイル名 ー D オプションをつけて cpr てデバッ ターゲットより新しいソースファイル名のリスト グした後 , 再コンパイルせずに lstrip コマンドてデバッグ情報を削除す れば , コンパクトな . exe ファイル を得ることがてきます。ただし , ー D3 と一 D4 オプションを使った場合 、 DEFAULT 、 ソースファイルの作成方法が記述されていない場合 , この文の次行から書かれてい は , 出力コード自体がデバッグし るコマンドを実行します やすく変更されますのて , 再コン .IGNORE ー i オプションと同じです パイルしたほうがよいてしよう。 .LMKPATH : ー 1 オプションと同じです また , デバッグて一 D2 オプションを 実行したコマンドがエラーコードを返してきたときは , この文の次行から書かれて . ONERROR 指定して lstrip を使えば , 最後に再 いるコマンドを設定します コンパイルする手間がなくなりま SET : name す。 環境変数 name を string に設定します =st 「 ing 誌面の関係上 , 今回取り上げら . SILENT : ー s オプションと同じです れなかったユーティリティは , ま たの機会にご紹介します。 匚④。 , ~ コ 覧 文 ョ シ プ オ 2 lnformation from Compiler Makers 161

2. 月刊 C MAGAZINE 1990年10月号

TabIe 3 ファイル八ンドルのニ重化 DOS ファンクション 45h ファイル八ンドルのニ重化 引数 AH=45h BX = ファイル八ンドル ー NT 21 h 返り値キャリー = 1 ファイル八ンドルの複製 TabIe 5 dup 関数 される を読み書きしても , 両方のファイル八ンドルのファイルポインタが更新 ル八ンドルを AX レジスタに返す。どちらのファイル八ンドルでファイル 機能 BX レジスタで指定されたファイル八ンドルをニ重化して , 新規のファイ AX = 新規のファイル八ンドル キャリー = 0 = 06h : 無効な八ンドル AX=04h : オープンされているファイルが多すきる 0 プログラマのための ' れる。このファンクションはファンクション 45h とともに使用して標準 ル八ンドルがすでにオープンされている場合 , コピーの前にクローズさ 指定された新規のファイル八ンドルにコピーする。 CX レジスタのファイ 機能 BX レジスタで指定されたファイル八ンドルをニ重化して CX レジスタで キャリー = 0 : 正常終了 = 06h : 無効な処理 AX=04h : オープンされているファイルが多すきる 返り値キャリー INT 21h CX = 新規のファイル八ンドル BX = 既存のファイル八ンドル 引数 AH=46h DOS ファンクション 46h 指定したファイル八ンドルへのコピー TabIe 4 指定したファイル八ンドルへのコピー TabIe 7 割り当てずみのファイル八ンドル 出力のリダイレクトに使用されることが多い int dup(handle) : int handle オープンずみのファイルノ、ンドル 返り値 > = 0 : 新しいファイル八ンドル ー 1 : 工ラー TabIe 6 dup2 関数 ファイル八ンドルの複製 int dup2 (oldhandle, newhandle) : int oldhandle : int newhandle : オープンずみのファイル八ンドル 新しいファイル八ンドル ファイル 八ンドル 0 1 2 3 4 役割 標準入力 標準出力 標準工ラー出力 補助入出力 プリンタ出力 テパイス名 CON CON CON AUX PRN stdprn C の相当する ファイルポインタ stdin stdout stderr stdaux 返り値 = = 0 : 正常終了 ー 1 : 工ラー バイプ パイプ機能もリダイレクトの仲間てす。 DIR ー SORT とするとディレクトリの結果がソートされ て表示されます。これは , DIR の標準出力→ SORT の標準入力 という接続を行っている結果てす。 リダイレクト機能は上記の入力のリダイ レクト , 出力のリダイレクトおよびパイプ 機能単体または組み合わせの総称て、す。 (TabIe 1 ) 。 という 3 つの部分から構成されています COMMAND.COM MSDOS. SYS ℃ . SYS MS-DOS は基本的に , やってるの ? リタイレクトは誰か 注 ) ファイルポインタから f ⅱ eno ( stdin ) でファイル八ンドルが取り出せる IO. SYS はデバイスドライバそのものて す。 CON, AUX, CLOCK などのキャラク タデバイスとドライプ A : , B : などのプロ ックデバイスからなります。 MSDOS. SYS は MS-DOS の本体て, シス テムファンクションの INT 20h ~ 3Fh て、呼び 出します。おなじみの DOS ファンクション Fig. 4 標準出力のリダイレクト ファイル八ンドル 1 ファイル八ンドル 1 の INT 21h の機能は MSDOS. SYS の機能て、 す。 COMMAND.COM は COPY, TYPE, DEL などの内部コマンドやバッチファイル を起動します。 それて、はリダイレクトやパイプの機能は この 3 つのうちどの段階て行われているのぞ ファイル八ンドル 1 を ファイルにリダイレクト ファイル 新 MS-DOS プログラミング入門 95

3. 月刊 C MAGAZINE 1990年10月号

五ロ はじめて学ぶプロクラー ニンク List 2 List 1 ⅱ stl. c ファイルのオープン・クローズ 2 : 4 : # i nc 1 ud e く std i 0. h > 6 : void main(void) F 比 E * f Ⅱ e 1 ; 8 : 9 : f 叩 en("myfile. xyz' f ⅱ e 1 fclose(filel); 13 : } ⅱ st2. c ファイルのオープン・クローズ 2 : 4 : # i nc lud e く s td i 0. h > 6 : void main(void) 8 : F I し E * f i I e l; 9 : fopen("abcde. xyz" f i 1 e 1 fc I ose (f i 1 e 1 ) : 12 : 13 : } て Fig. 1 のような状態が確立されます。ファ イル ( デバイス ) をクローズすることによっ て , その結合は解消されます。 したがってファイルを取り扱う ( 読み・書 き ) ときには , そのファイルをオープンした りクローズすることが必要になってきます ( 注 : 本稿て、は , データをファイルから読む ( ファイルへ書く ) こととストリームから読 む ( ストリームへ書く ) ことを同じ意味て、用 List 3 1 i st3. c ファイルのオープン・クローズ 2 : 4 : #include く stdio. h> 5 : 6 : void main(void) char FiIeName[100]; 8 : F I し E *f i I e 1 : 9 : printf("lnput file name : PiI eName) : scanf("%s" 12 : if ((filel = fopen(FiIeName, printf("YnYnYafi le open error 14 : exit(-l); 15 : } e 1 se { printf("Yn%nSuccess fi le open%nyn") : 17 : fclose(filel); 20 : } = NULL) : XsYnYn ” FileName); いています ) 。 ファイルのオープン・クローズ ファイルに関して何か処理をしようとす るときには , 必ず次の手順を取ります。 1. ファイルのオープン 2. なんらかの処理 3. ファイルのクローズ こて、は重要なファイルのオープン・ク ローズに関するお話をしましよう。 前述のようにファイルをアクセスするに は前もってファイルをオープンする必要が あります。ファイルをオープンする場合 , 基本的に次の情報が記述されていなくては なりません。 ①どのファイルを ( ファイル名 ) ②どのようなモードで (read, write, append など ) そして , オープンしたファイルが , ③どのストリームと結合しているか を知る必要があります。 これを行ってくれ るのが fopen 関数てす。 はしめて学ぶ C プログラミング 133 TabIe 1 ファイル関係の関数・マクロ 1 ファイルのオープン・クローズ 関数名 fopen ・形式 FILE * fopen(const char *filename, const char * mode) ; ・機能 指定されたファイル名のファイルをオープンし , ファイルとプログラムを結ぶストリームと結 合する f 「 eopen 関数名 ・形式 FILE * freopen(const char * filename, const char * mode, FILE * stream) , 指定されたファイルをクローズし , その後同じファイルをオープンする。 mode を変更するとき ・機能 に用いる fclose 関数名 ・形式 int fcIose(FlLE * stream) , バッフアの内容をファイルに書き出したのちファイルをクローズする ・機能 関数名 fflush ・形式 int ffIush(FlLE *stream) , 出力バッフアに残っている内容を指定ファイルに書き出す。ファイルのクローズは行わない ・機能 2 ファイルからの入力 マクロ名 getc ・形式 int getc(FILE *stream) ,

4. 月刊 C MAGAZINE 1990年10月号

力を行います。したがってこれらの関数を 用いる場合には , 「どのファイルと入出力を 行うか ? 」をシステムに知らせなければい けません。この目的のために fopen したとき に得られた , 「ストリーム制御変数へのポイ ンタ」を使うわけて、す。各関数 , マクロの 用法は Table 1 や本誌 4 月号を参照していた こて、はなるべく例題を 挙げて説明しましよう。 例 1 「 ASC Ⅱファイルの内容をディスプレ イに表示するプログラム ( List 4 ) 」 このプログラムて、は , main 憫数の引数の 機能を用いて , プログラム名ファイル名固 と入力するルールにしてあります。そして , 引数の数が合わない ( a 「 gc が 2 て、ない ) ときに usage: プログラム名 FileName <ret> と標準出力に表示して処理を中断していま す。また , ファイルがないなど fopen 時に工 ラーが生じたら , open file error : ファイル名 と表示して , やはり処理を打ち切っていま す。そしてファイル ( ストリーム ) から 1 文字 取ってきてはその文字を標準出力に書き出 す , ということを入力ファイルが終了する まて、続けます。プログラム中の getc は fgetc に変更してもまったく同じ働きをします。 putchar(c) ; ・形式 int feof(FILE * stream) : ・機能ファイルの終わりに達したかどうかをチェックするマクロ。 EOF に達していれは真 , そうでな ければ偽を返す マクロ名 fe 「「 0 「 ・形式 int fe 「「 0 「 ( 日 LE * stream) : ファイルの読み書き中にエラーが起こったことがあるかどうかをチェックするマクロ。工ラー ・機能 が生じていたら真 , 工ラーがなければ偽を返す clearerr 関数名 ・形式 void clearerr(FILE * stream) : ・機能 ファイルについてのエラーおよび EOF の状態を解除する TabIe 2-1 ファイルのオープンモード mode 意味 read モード。ファイルはすでに存在していること write モード。ファイルがなければ新設 , あれば空にされる append モード。ファイルがなければ新設され , あれば , ファイルの現在位置をそ のファイルの終わりに設定する ファイルの更新のために「 ead / w 「 ite モードでオープンする。 ただしファイルはすでに存在すること ファイルの更新のために「 ead / w 「 ite モードでオープンする。ファイルがなければ 新設され , あれば空にされる ファイルの更新のために「 ead / w 「 ite モードでオープンする。ファイルがなければ 新設され , あればアベンドされる は , TabIe 2-2 文字 意味 テキストモード バイナリモード TabIe 3 標準テキストストリーム ストリーム stdin stdout stderr これらの他に OS ( 処理系 ) によってはプリンタ出力 , 補助出力など用意されているものもある 通常割当テパイス 呼び名 標準入力 標準出力 標準工ラー出力 キーボード 画面 画面など は , PUtc(), stdout) ; あるいは , fputc(), stdout) ・ - としても同じ働きをします。 List 5 List 4 list5. c A S C I I ファイルの表示その 2 2 : 4 : # i ncl ud e く std i 0. h 〉 5 : 6 : VOid main(int argc, char *argv[]) 8 : i nt C : 9 : F I し E 料 nF i 1 e : if (argc ! = 2 ) { fprintf(stderr, ex i t ( ー I) : 1 ist4. c A S C I I ファイルの表示 2 : 4 : #include く stdio. h> 5 : char *argv[]) 6 : VOid main(int argc, 8 : int c: 9 : F I し E * I nF i I e : if (argc ! = 2 ) { printf("usage ・ . %s FileName \ 心 く ret> exit(-l); argv[0]) : %s Fi leName く ret> Yn ” usage: , argv [ 0 ] ) : CMAGAZINE 19 10 136

5. 月刊 C MAGAZINE 1990年10月号

三ロ はじめて学ぶプロクラミンク List 1 て、は w すなわち write モードて、ファ イルをオープンしていました。ファイルオ ープン時に , そのファイルは書き込み専用 て、ある , と指定をしておいたわけて、す。 の指定を行うのが fopen 関数の第 2 引数て、 す。この引数の取り得る値を TabIe 2 に示し ました 0Table 2 ー 1 がファイルのオープンモ ードを表しています。この指定によってフ アイルは読み , 書き , 追加 , 読み出し / 更 新 , 書き込み / 更新 , 追加 / 更新の指定がて、 きます。これに加えて TabIe 2 ー 2 の文字を付 加することにより , テキストモード , バイ ナリモードの指定がて、きます。 さて , List 2 を実行してみてください のプログラムては read モード <abcde. xyz と いうファイルをオープンしています。 read モードはそのファイルがすて、に存在するこ とを前提にしています。しかし , このファ イルは用意してありません。ところが List 2 のプログラムを実行しても , ファイルのオ ープンは失敗しているはずなのにとくに工 ラーがて、るとか , 変わったことはなにも起 こりません。逆にいえばファイルオープン 時のエラー管理は自分自身て、行わなければ ならないわけて、す。 fopen 関数て、はファイル のオープンに失敗した場合 , NULL が返っ てくることになっていますのて、 , これを利 用したエラー管理の例を List 3 に示します。 fopen て、オープンされたファイルに対して 実際に入出力を行うためには , getc, fgetc, fgets, putc, fputc, fputs, fscanf, fprintf などといった関数 ( マクロ ) を用います。 れらの関数は以前にててきた , getchar, putchar, gets, puts, scanf, printf とほぼ同じ働きをします。 scanf , P ⅱ ntf など はすて、にオープンされている , 標準テキス トストリーム (Table 3 参照 ) に対して読み書 きを行っていました。それに対し fscanf, fp 「 intf といった今回説明する関数などは , ユ ーザがオープンしたファイルに対して入出 はじめて学ぶ C プログラミング 135 ・形式 int fscanf()l LE * stream, const char * format, argl, arg2, ・機能 ファイルから文字列を入力し , 入力書式制御にしたがって変換し , 変数に値を格納する 関数名 printf ・形式 int printf(const char *format, argl, arg2, ・機能 指定された変換仕様にしたがって各引数の値を標準出力へ文字列として出力する 関数名 fp 「 intf ・形式 int fprintf(FlLE *stream, const char *format, a 「 91 , a 「 92 , ・機能 指定された変換仕様にしたがって各引数の値を文字列に変換しそれをファイルに出力する 5 プロック入出力 関数名 fread ・形式 sizet fread(void * ptr, size t size, size t n, FILE * stream) , ・機能 入力ストリームからプロックでテータを読み込む。プロックの形式は , 大きさ size の要素が n 個 からなる 関数名 fw 「 ite ・形式 size t fwrite(const VOid * ptr, size t size, size t n, FILE * stream) , ・機能 大きさ size の要素が n 個からなるプロックテータをストリームに書き込む 6 ファイル位置設定 関数名 fsee k ・形式 int fseek(FILE *stream, long Offset, int origin) , 0 「 igin の位置から 0 幵 set で指定されたバイト数だけファイル位置を移動する ・機能 関数名 ftell ・形式 long ftelI(FlLE *stream) , ・機能 ファイルの現在位置を調べる 関数名 rew ・ ind ・形式 VOid rewind(FILE * stream) , ファイルの位置をそのファイルの先頭に移動する ・機能 関数名 fgetpos ・形式 int fgetpos(FILE * stream, fpos t * pos) , ファイルの位置を得て変数に格納する。この関数はれ関数を用いて実現できる ・機能 関数名 fsetpos ・形式 int fsetpos(FILE * stream, const fpos t * pos) , ・機能 指定された位置にファイルの位置を移動する。この関数は fseek 関数を用いて実現できる 7 ファイルの状態を表す マクロ名 feof 匚 , ーロ

6. 月刊 C MAGAZINE 1990年10月号

やはりエラーメッセージは標準工ラー出 力に出したい , と考えるならば , 工ラーメ ッセージを出す printf 関数を fP 「 intf 関数に変 更し , 出力ストリームを stde 「「にすればよい て、しよう (List 5 ) 。 例 2 「ファイルをコピーするプログラム ( List 先のプログラム同様 main 関数の引数を利 用します。用法は , プログラム名ファイル名 1 ファイル名 2 固 という形を取ります。ファイル名 1 のファイ ルをバイナリモードて読み込み用にオープ ンし , ファイル名 2 のファイルをやはりバイ ナリモードて、書き込み用にオープンします。 オープンした後は , 先ほどと同様ファイル の終わりまて、 1 文字ずつ読んて、は書いてを繰 り返します。 List 6 をちょっと改造してみましよう。 List 7 はほとんど List 6 と同じプログラムて すが , ファイルの終わりを検出する feof を利 用しています。 feof は , ファイルが終わりに達していたら非 0 , 達していなかったら 0 を返します。プログラム中て、は , while( ! foef(lnFiIe)) と使用しています。ファイルが終わりに達 していない間処理を繰り返す , という記述 て、す。これによって , ファイルの終わりま て、 , 1 文字ずつ読み書きを繰り返すことがて、 きるわけて、す。 if((c=fgetc(lnFiIe)) = =EOF) という形のファイルエンドの検出は , fgetc 関数の機能を利用しています。ストリーム がファイルの終わりて、ある場合 ( これは feof て、識別可能 ) は EOF を返す , という働きが fgetc にあるだめて、す。しかし , ストリーム がバイナリモードて、オープンされている場 合には , ファイルの終わりは feof を , 工ラー の検出には fer 「 0 「を用いるべきて、しよう ( コ ラム 1 参照 ) 。したがって List 6 より List 7 の ほうがお勧めて、きるスタイルて、す。 例 3 「ファイルを 1 行すっコピーするプロ グラムを fgets, fput 関数を用いて作 ってみましよう。コピーするファイ CMAGAZINE 19 10 138 List 7 8 9 0 1 つなっ 0 っ 0 っ 0 fcIose(InFiIe); fc I ose(0utPile) : List 8 2 : ⅱ st8. c ファイルの行ごとコピー 4 : #include く stdio. h> 5 : 6 : void main(int argc, char *argv[]) char str[256] : 8 : 9 : int count; FI し E *InFile, *0utFile; if (argc ! = 3 ) { 12 : fprintf (stderr, exit(-l); i f ((InFiIe = fopen(argv[l], = NULL) { : XsYnYn", argv[l]) : fprintf (stderr, "open f i le error exit(-l); i f ( (0utF ile = fopen (argv [ 2 ] , 20 : fprintf(stderr, "open fi le : XsYnYn", argv [ 幻 ) : error exit(-l); 22 : 23 : 24 : 25 : 26 : 28 : 29 : 30 : 32 : 33 : 34 : } InputFi 厄 OutputFi le く ret> Yn", argv[0]) : usage: Xs count ニ 0 : while (fgets(str, 256 , InPi le) ! = N 乢い { count 十十 : fputs (str, OutFiI e) : printf("%d 行転送しました Yn" fcIose(InPile); fcl ose(OutFiIe) : count) : List 9 1 ist9. c ファイルの行ごとコピーその 2 2 : 4 : #include く stdio. h> 6 : void main(int argc. ・ char *argv[]) char str [ 256 ] : 8 : 9 : int count; P I し E nF i 1 e, *0utF ⅱ e : if (argc ! = 3 ) { fprintf(stderr, exit(-l); if ((InPile = fopen(argv[l], = NULL) { fprintf (stderr, ” open file error exit(-l); i f ( (0utP ile = fopen (argv [ 2 ]. 20 : fprintf(stderr, open file error 22 : exit(-l); 23 : 24 : 25 : 26 : 28 : InputFile 0utputFi le く ret> Yn", argv[0] ) : usage: %s : Xs%nYn", argv[l]); : XsYnYn", argv[2]) : count = 0 : while (fgets(str, 256. InFile) = N 乢し ) { count 十十 : fputs (str, 0utFil e) : fputs (str, stdout) : printf("Xd 行転送しました Yn" count) :

7. 月刊 C MAGAZINE 1990年10月号

Get Thee Behind Me, 5POW0 Of UNIX! コールしたプロセスの親の PID を返します。 プロセスが自分の親の PID を変えることはて きません。 親・子という関係があるため , ( 複数の ) プロセスはツリー状の階層構造になります。 どの UNIX システム上ても , プロセスのツリ ーのルートは , スワッパと呼ばれる特殊な プロセスてす。スワッパは , システムのプ ート時に , いちばんの PID のプロセスとして 生成されます。スワッパは , プロセスへの メモリの割り当てを管理し , CPU 時間の割 り振りにも影響します。スワッパから生成 される最初の子 ( ファイル /etc/init の実行に よる ) は , プロセスディスパッチャて , これ にも 1 の PID が割り当てられます。ューザが 起動するすべてのプロセスは , このプロセ スディスパッチャの子孫てす。スワッパの そのほかの子は , すべてオペレーティング システムのカーネル内部のコードだけを実 行する , 特殊なシステムプロセスてす。ス ワッパとプロセスディスパッチャは , シス テムの全寿命期間にわたって存在します。 List FILE *fp = NU しし : int main(int argc. char *argv ロ ) int fork() : 2 : #include く stdlib. h> #include く stdio. h> UNIX は , プロセステープルと呼ばれる内 部的なデータ構造に , プロセスの行動を記 録しています。システム上のそれぞれのプ ロセスが , このテープル上に自分の記載欄 をもっています。プロセステープルは , ps コマンドて見ることがてきます。 -e オプシ ョン ( すべてのプロセス ) やー f オプション ( 網 羅的表示 ) を指定すると , ps コマンドはテー プル上のすべてのプロセスに関する情報を 表示します。 プセスの生成 新たなプロセスは , システムコール intf0 「 k ( ) を使って生成します。この関数は , コール したプロセスの子を作ります。子プロセス は , ほとんど親プロセスの複製て、あり , f0 「 k がコールされる前には存在しないのに , 自 分の親と同じ場所から実行をヾ再開〃しま す ( fo 「 k コールのリターン時に ) 。 f0 「 k の戻り 値て , 親と子が簡単に区別てきます。子プ ロセスの PID が親へ返され , 子へは値 0 が返 1 : 3 : 4 : 5 : 6 : 8 : 9 : 12 : 13 : 14 : 17 : 19 : 20 : 22 : 23 : 24 : 25 : 26 : 28 : } / * ファイルをオープンして 1 行を書き込む * / fputs("0ne line written tO file. Yn", (p) : exit(EXIT_FAI し URE) : perror("fork") : if (fork() / * 新たなプロセスを作る * / exit(EXIT_FAI し URE) : perror("fopen") : if ()p = NUL し ) { fopen("outfile. txt", exit(EXIT_SUCCESS) : fc lose (fp) : / * ファイルをクローズ ( バッフアは自動的にフラッシュ ) * / されるのてす。ェラー時には , 値ー 1 が親に 返され , 新たなプロセスは生成されません。 List 1 の C のコード片て , f0 「 k の使い方の概 要を示します。 親プロセスの複製のなかには , そのファ イルディスクリプタテープルも含まれます。 ファイルディスクリプタは , プロセスがオ ープンファイルを参照するために使う整数 値て、す ( 訳注 : MS-DOS のファイルハンドル に相当 ) 。この整数値をシステムコールが , そのオープンファイルを伴うプロセスのフ ァイルディスクリプタテープルの , インデ ックス・・ ・・テープル内の何番目〃 ルディスクリプタにリンクされているファ す。 ( 複数の ) プロセスが , 継承したファイ スクリプタ間に作り出される関係と同じて dup によって , 同じプロセスのファイルディ ドを共有します。これは , システムコール し , 同じファイルポインタとアクセスモー ステムファイルテープルの同一の欄を共有 タは , それぞれが独立てありながらも , シ がって , 継承されたファイルディスクリプ プロセスの生成時に複製されません。した テムファイルテープルはグローノヾルて , 新 リプタテープルをもちますが , 一方 , シス 各プロセスが , 自分のファイルディスク テープルの欄ヘリンクされます。 使用欄が割り当てられ , システムファイル に , ファイルディスクリプタテープルの未 ープルの未使用欄が割り当てられます。次 ープンされるときに , システムファイルテ プルにストアされています。ファイルがオ モード ( 例 : リードオンリー ) が , このテー ポインタ ( ファイルの現在位置 ) とアクセス ルを制御するために使われます。ファイル ばれる第 2 のデータ構造が , オープンファイ さらに , システムファイルテープルと呼 す。 はすべて , 子においてもオープンしていま たときに , 親がオープンしていたファイル ープルが複製されるのて , fo 「 k がコールされ して使います。ファイルディスクリプタテ 38 CMAGAZINE 1 10

8. 月刊 C MAGAZINE 1990年10月号

しようか ? ( IO. SYS はデバイスドライバて すからこれは候補から外してもよいて、しよ この点を確認するためにちょっとしたテ ストプログラムを組んて、みましよう。 List 1 ( test 。 ut. c ) は標準出力に出力するなんの変哲 もないテストプログラムて、す。この List 1 を , testout > $$$. out として起動する 2 種類のプログラムを作成し てみます。 List 2(test1. c) は List 1 を直接起動するテ ストプログラム。 List 3(test2. c) は COM MAND ℃ OM を経由して起動するテストプ ログラムて、す。 List 3 は , command /c testout > $$$. out を実行していることになり system 関数て、 , system("testout > $$$. out") : とするのとほとんど同じことて、す。 プログラムの起動は DOS ファンクション 4B00h(TabIe 2 ) て、行われ List 2 と List 3 の spawnvp 関数もこのファンクションを使用 しています。したがって List 2 て、リダイレク トが行われれば , MSDOS. SYS がリダイレ クトの機能を実行していることになり , List 3 て、リダイレクトされれば , COMMAND. COM がリダイレクトの機能を実行している ことになります。 Fig. 3 が List 2 , List 3 の実行結果て、す。 この結果から .COM/AND.COM リダイレ クトの機能を実行していることがわかりま す。 リタイレクトの原理 リダイレクトを COMMAND.COM が実行 しているということは , DOS ファンクショ ンのどれかを用いてリダイレクト機能を実 現していることになります。それて、はどの DOS ファンクションを用いているのて、しよ COMMAND.COM を解析してみ要簡単 にわかるのて、すが , 時間的に調べる余裕が Fig. 5 子プロセスの標準出力のリダイレクト ファイル八ンドル 1 標準出力ーーーーーーー→コンソール ( CON ) ファイル八ンドル 1 を ファイルにリダイレクト ファイル八ンドル 1 ファイル ァ ータ ファイル八ンドル 1 ァータ ーーー - ーーーーー→標準出力 コンソール ( CON ) ファイル 子プロセス起動 ファイル八ンドル 1 を もとに戻す Fig. 6 子プロセスの標準出力のリダイレクト 標準出力 ( ハンドル 1 ) を退避 ↓ 標準出力 ( 八ンドル 1 ) をファイルに 再割り当てする 子プロセス起動 ファイルに割り当てた標準出力 ( 八ンドル 1 ) をもとに戻す ↓ ↓ 96 CMAGAZINE 19 10

9. 月刊 C MAGAZINE 1990年10月号

ボーランドジャパン 0 「 m 面 00 from (ompiler ma 「 5 TurboC 2.0 f Ⅲ po ツで多角形の頂点の数が 680 以上になると , 描画されなくな ってしまうのはなぜですか。 グラフィックスルーチンの中 には f Ⅲ po ツや flOOdf Ⅲのようにバッ フアを用いるものがあります。 の場合は ,setgraphbufsize< ノヾッ フアサイズを増やしてください デフォルトのバッフアサイズは 4K ノヾイトて、す。 setgraphbufsize は initgraph より前に呼び出す必要が あります。 0 getenv で環境変数を得ること ができません。 A UNIX などの OS て、は環境変数 として大 , 小文字の両方を使えま TabIe 1 0 すが , MS ー DOS て、は大文字しか設 定て、きません。 getenv の引数を小 文字にしてしまうと , ー空文字列し か返されません。また , 環境変数 の両側にスペースが入っ ている場合も正しく認識されませ ん。 fopen の各モードは , それぞれ どのような違いがあるのですか。 fopen の各モード (), w, a, r 十 , w 十 a 十 ) には , それぞれ Table 1 のような違いがあります。 w , a はそれぞれ , 「既 存のファイルを読む」 , 「新規ファ イルをオープンし , 書き込む ( 既存 のファイルがあれば , 上書きされ る ) 」 , 「既存の領域を変更せず , 内 容を追加 , 書き込みするためにオ 0 A 、Ⅵ既存のファイルを読み込むためにオープンする 既存ファイル 追加部分 R 可能 , W 不可 R/W 不可 、、 w ″ファイルを書き込むために新規にオープンする R 不可 , W 可能 書き込み部分 、、 a ″ファイルの終わりに書き込むようにオープンする % 十″ファイルの終わりから更新用としてオープンする R 可能 , W 可能 書き込み部分 、、 W 十″ファイルを読み書きのために新規にオープンする R 可能 , W 可能 R 可能 , W 可能 追加部分 既存ファイル 既存ファイルを更新用としてオープンする R 不可 , w 不可 R 不可 , W 可能 既存ファイル 追加部分 ツ十″ ープンする」ことを意味します。 十〃は , 読み書きの両方を行う を十 b 〃 ことを意味します。また , のように最後に、、 b 〃や社〃が付加 された場合は , バイナリファイル かテキストファイルのどちらてあ るかを意味します。 市販のエデイタて編集したファ イルを , テキストモードてアベン ド ( モードつしても , 追加した 部分が表示されない ( 追加されてい ないように見える ) ことがあります が , これはもとのファイルの最後 に 1Ah(CTRL-Z) が書き込まれて いるためて、す。アベンドモードて、 は , もとのファイル内容は変更て、 きないため , ファイルの最後の 1Ah は自動的には削除されません。 の場合は ,List 1 のようなプログラ ムて、対応してください また , ランタイムライプラリソ ースをおもちの方は , ー DCPM ctIZ = 1 というオプションをつけて open. cas, C10 . C をコンノヾイノレし てください。ここて作成した叩 en. obj, clo .0bj をリンクすると fp=fopen(filename, " 「十 " ) : fseek(fp, OL, SEEK END) : とするだけて、 CTRL ー Z を自動的に 削除して追加書き込みがてきるよ うになります。 tcc -l.. *include -linclude ー 0 -d -c -wpro -mt List 1 clearerr(fp) : ニ EOF) { if (fgetc(fp) ー 1 し , SEEK_END) : 2 : fseek(fp, fopen()i lename, 7 : 5 : 4 : 3 : fseek(fp, OL, SEEK_END) : 6 : } e I se { ー 1 し SEEK_END) : fseek (fp, ー DCPMctlZ=1 open. cas close. C 0 ディスクドライプに フロッ get を抜けると解放されます。スタ になります。このスタック領域は のは , get 関数のローカルスタック 関数の返すポインタがさしている に確保されます。したがって , get ローカル変数て、すから , スタック char s [ 10 ] は get 関数の中の A ですか。 列が正しく表示されないのはなぜ List 3 のように入力した文字 0 getdisk を併用してください トドライプを変更しないために イプを変更してしまうのて、 , カレン ただし , setd isk はカレントドラ られます。 の総数は , setdisk を呼び出すと得 また , 接続されているディスク て、きます (List 2 参照 ) 。 ライプにアクセスすることて判別 録した後 , getcu 「 di 「て、指定したド ha 「 de 「「て、エラーハンドラを登 A でしようか。 するには , どのようにすればよい ピーが入っているかどうかを判別 既存ファイル 追加部分 R 可能 , w 不可 R 可能 , W 可能 ※ R = 読み込み , W = 書き込み 158 CMAGAZINE 19 10

10. 月刊 C MAGAZINE 1990年10月号

五ロ はじめて学ぶプログラー ニンク List 4 List 5 if ((InFile = fopen(argv[l], printf("open file error exit(-l); if ((InPile = fopen(argv[l], = NU しし) { fprintf(stderr, open fi le error : XsYnYn" exit(-l); argvC1]) : -4 ド 0 々ー 8 0 、 1 り 0 っ 4 1 よ、 1 1 よ 41 1 よ、 1 っ 0 つなつなつなっ 0 4 0 れ 0 行ー 8 0 11 っ 0 っ 0 4- 、 1 1 1 ー 14 1 一 1 よっ 3 り 0 り 0 00 っ 0 = NUL し ) { : XsYnYn", argv[l]) : while ()c = getc(InFiIe)) ! = EOF) putchar (c) : fclose(InFile); while ()c = getc(InPiIe)) ! = EOF) putchar(c) : fcIose(InFile); List 6 コラム 1 テキストモードと ノヾイナリモード fopen のモード指定には , テキストモード とバイナリモードとがあります。テキスト モードではファイルをテキストファイルと してオープンしバイナリモードではファ イルをバイナリファイルとしてオープンし ます。それぞれのファイルの定義は以下の ようになっています。 テキストファイル 行を構成する , 整列した文字の列 ( 行端 には改行文字が付加されている ) からなる テキストで構成されているファイル バイナリファイル すべての制御文字をふくみ得る , 整列 された文字の列であるパイナリからなる ファイル。データの内部表現をそのまま 記憶し得る ふたつの形が混在して少々めんどうです が , かといってバイナリだけにしてしまう と , 不都合が生じてきます。 たとえば , テキストファイルでは行端の 改行文字は非常に重要な句切りとなってい ます。 OS に応じて改行文字のコードは異な るので自動的にコード変換されている場合 がほとんどです。ところが , バイナリモー ドにするとこのコードの自動変換がされす , 一切を加工しないでデータをやりとりしま す。テキストファイルでファイルの終了と 決まっているコードですら , 一般のデータ として処理してしまうため混乱を生じてし まうこともあるのです。 逆にファイルのコピーをしたいようなと きには , データの加工は一切必要ありませ んから , List 6 , 7 のようにバイナリモード でファイルをオープンして使います。 1 ist6. c ファイルのコピー 2 : 4 : #include く stdio. h> 5 : 6 : VOid main(int argc, char *argvC]) 8 : int c; FI し E *InFile, *0utFiIe; 9 : if (argc ! = 3 ) { fprintf(stderr, exit(-l); ((InFile = fopen(argv[l], i f fprintf(stderr, open fi le error exit(-l); if ((0utFile = fopen(argv[2], fprintf(stderr, "open fi le error 20 : exit(-l); 22 : 23 : 24 : 25 : 26 : 28 : 29 : } usage: %s lnputFiIe OutputFile く ret> argv[O]) : : XsYnYn", argv[l]) : : XsYnYn", argv[2]) : while ()c = fgetc(InPiIe)) ! = EOF) fputc(), 0utFi (e) : fclose(InFiIe); fclose(0utPi (e) : List 7 2 : list7. c ファイルのコピーその 2 4 : #include く stdio. h> 5 : 6 : VOid main(int argc, char *argv[]) 8 : int c; 9 : FILE *InPile, *0utFile; if (argc ! = 3 ) { fprintf(stderr, exit(-l); 14 : i f ((InPile = fopen(argv[l], fprintf(stderr, open f i le error . XsYnYn", argv[l]) : exit(-l); if ((0utFi le = fopen(argv[2], 20 : fprintf(stderr, "open file error . XsYnYn", argv[2]) : exit(-l); 22 : 23 : 24 : 26 : usage: Xs lnputFile OutputFile く ret> Yn", argv[0]) : while (!feof(InFile)) { = fgetc(InPile) : C fputc (), 0utFi (e) : はじめて学ぶ C プログラミング 137