ファイル - みる会図書館


検索対象: 月刊 C MAGAZINE 1992年6月号
79件見つかりました。

1. 月刊 C MAGAZINE 1992年6月号

のファイルポインタ ( ファイルに関する情報 を格納する場所を指すための特別な変数 ) を 用意する命令て、す。 宀言て、は変数名の前に * 印が必要て、す。 もし fl , f2 というふたつのファイルポインタ が必要なら , FILE *fl, *f2 ; のように , それぞれに * 印をつけます。 ポインタとか特別な変数とか能書きを並 べましたが , その実体を理解する必要は当 分ありません。 C 言語を使う者が知っていな ければならないことは , 以下に述べるほん の一握りの事柄て、す。 ・ファイルを操作するには , 上に述べた ファイルポインタという変数を用意す ・ファイルに何かを書き込むには , ファイ ルを「書き込み ( w ) 」モードて、開く ( オー プンする ) 。具体的には , オープンした いファイルの名前が spock. txt なら , f=fopen ("spock. txt", "w") ・ とする。もし同名のファイルがあれば 消す。、、 w クを、、 a クとすれば , 同名のファ イルがあれば末尾につけ加える ( アベン ドする ) 。 ・既存のファイルの内容を読み出すには , ファイルを「読み出し ( r ) 」モードて、オー プンする。具体的には f=fopen ("spock. txt" のようにする。 ・もしファイルのオープンに失敗した ( 工 ラーが起きた ) なら , 変数 f には NULL と いう特別の値が入る。ファイルをオー プンしたなら , List 5 の のように , f が NULL て、ないかどうかチ ェックする必要がある。 ・ファイルポインタ f のファイルがオープ ンて、きたなら , そこに書き込むには そこから読み出すには fprintf(f, fscanf (f, 92 C MAGAZINE 1992 6 ァイルポインタを与えることを除いて , とする。これらの関数は , 第 1 引数 ( こフ TabIe 3 1 文字単位の読み書き 関数 putchar(c) : c=getchar( ) : putc (), f) : c=getc (f) : c : 文字 , f : ファイルポインタ 今まて、使ってきた printf( ) , scanf( ) と用法は同じて、ある。 ・ファイル操作が完了したなら , 最後に ファイルを閉じる ( クローズする ) 。そ fclose(f) ; のための命令は なお , List 5 て、は画面に 1 文字ずつ文字を の部分て、ある。 r=fclose (f) ; のチェックが List 5 の 確には EOF という定数の値 ) が戻る。 あるが , 工ラーの際には 0 て、ない値 ( 正 て、ある ofclose() の戻り値は通常は 0 て、 ー 1 て、す。 けてあります。 EOF の実体は伝統的には SS のような , 読んて、意味がわかる名前をつ C 言語て、は , 定数に EOF や EXIT SUCCE イル末 ) が語源て、す。 の部分て、す。なお , EOF は endoffile( ファ c=getc(f) ; を返します。このチェックが List 5 の getc( ) や getchar( ) は EOF という定数の値 入力が尽きたりエラーが生じたりすると , とします。 putchar(c) ・ または int 型の変数 c を介して putchar(' A' ) ; 画面に文字く A > を書くには しては int 型て、宣言します。 す。 TabIe 3 て、は , c は文字て、すが , 変数と この類の命令を TabIe 3 にまとめておきま 字を書き込む命令 getc ( ) が使ってあります。 書く命令 putchar( ) , ファイルに 1 文字ずっ文 時間計測ソフト WATCH これまて、に述べたことを使って , 実用に なるソフトを作ってみましよう (List 6 ) 。 このソフトは , 私がかって勤めていた高 校のマラソン大会て計時に使ったものて、す ( 若干簡単にしてあります ) 。 学校には時間を印字て、きる時計もありま したが , 結果を表計算ソフト Lotus 1 ー 2 ー 3 て、 処理するために , ファイルに時間を書き出 すことが必要になりました。そこて、ノート パソコンをストップウォッチ代わりにしま このソフトは , 初代ダイナブックから PC ー 9801NS / T まて、 , 種々のノート型パソコン て、実際に使い , 動作を確認しました。 使用法は , スタートもゴールもキーを 押すだけの簡単なものて、す。ノートパソコ ンのバッテリーを節約するために , 途中て、 終了して電源を切ってもかまわない仕様に なっています。 具体的には ,time. dat という名前のテキス トファイルにスタート時の time (NULL) の 値とゴールまて、の秒数を記録します。すて、 に time. dat というファイルがあるなら , スタ ート時刻をそれから読み取って , ゴールま て、の秒数を追加していきます。このソフト には , まだ勉強していない命令がいくっか ありますが , 気にせすやってみてください 機能 画面に書く キーボードから読む ファイルに書く ファイルから読む LSI Cー86 の YincludeYstdio. h ヘッダファ イルにも #define EOF ー 1 と定義してあります。しかし , C 言語の規格 には「 EOF は負の定数て、ある」と書いてある だけて、す。

2. 月刊 C MAGAZINE 1992年6月号

マイクロ、 . 厚ト lnformation from Compiler Makers 今回は , MS-CVer. 6.0 の LIN K. EXE に関する機能として , 応答 ファイルの利用とオーバレイプロ グラムの作成について解説いたし ます。なお , これらの機能の解説 は , MS-CVer. 6.0 付属のオンラ インヘルプから参照することが可 能て、す。 応答ファイルとは MS-CVer. 6.0 を使って , プロ グラムを開発する場合 , PWB や M AKE ファイルを使用することて、 , 実行ファイルを自動的に作成する ことがて、きます。しかし , このほ かにもリンクの設定や複雑なリン ク作業の手順を保存して , この手 順に従って LINK. EXE を実行する 方法があります。 MS-C Ver. 6.0 に付属のリンカ て、は , 応答ファイルに LINK. EXE の行う作業を記述して , LINK. EX E の実行時に , この応答ファイルを 指定することにより , 一連の作業 を手続き化することがて、きます。 応答ファイルの指定 応答ファイルを使って LIN K に 指示するには , DOS のプロンプト て、次のように入力します。 凵 NK @responsefile <responsefile> フィールドには , コマンドラインまたは LINK プロン プトに対する入力と同じ内容が記 述されたファイルの名前を指定し ます。このファイルて、は , それぞ れの入力項目は別の行に置くか , カンマて、区切ります。 <responsefi le > フィールドに指定て、きる応答フ 応答ファイル 148 C MAGAZINE 1992 6 アイルはひとつだけて、す。 ! 特別な機能 ・ LINK コマンドラインまたは LIN K プロンプトのどの場所て、も , そ こから後の入力を応答ファイル を使って行うことがて、きます。 応答ファイルに , 残りのフィー ルドやプロンプトに対するすべ ての入力事項が含まれていない 場合 , LINK は不足分に対するプ ロンプトを表示します。 ・応答ファイルて、は , キーポード から入力する場合と同じ方法て、 , 特殊文字を使用て、きます。たと えば , プラス記号 ( 十 ) を使って 改行したり , セミコロン ( ; ) を 使って残りすべてのプロンプト に対してデフォルトの応答を選 ぶことがて、きます。 ・ LINK は , 画面上にプロンプトと 応答ファイルからの入力内容を 表示します。応答ファイルから の入力が受け入れられない場合 , LINK はプロンプトを表示して応 答を待ちます。ただしソ B 〃オプ ションを使うと , このプロンプ トは表示されません。 ・オプションは , 応答ファイル中 のどこにあっても構いません。 応答ファイルによるリンク例 応答ファイルの例を Fig. 1 に示 します。応答ファイル名を FUN. L NK とした場合 , コマンドは次のよ うになります。 LINK @FUN.LNK この場合 , LINK は次の一連の動作 をします。 1. FUN, TEXT, TABLE, CAR E の 4 個のオプジェクトモジュー ルを FUN. EXE という名前の実 行ファイルにリンクします。 2. FUNLIST. MAP というマップ ファイルを作成します。 3. 実行ファイルを作る前に一時停 止します。ここて、ディスクを交 換することもて、きます。 4. パプリックシンボ、ルとアドレス をマップファイルに入れます。 5. , ライプラリファイル GRAF. LIB から , 必要なすべてのルーチン をリンクします。 オーバレイプログラム の作成 GRAF. L 旧 FUNLIST /PAUSE /MAP FUN TEXT TABLE CARE Fig. 1 応答ファイルの例 ります。 ードが必要なため , 実行は遅くな が , ディスクからのロードや再ロ 使うとメモリが少なくて済みます きません。一般に , オーバレイを ドだけて、 , データはオーバレイて、 とき , オーバレイて、きるのはコー を作成することが可能て、す。この いメモリ上て、動作するプログラム 分を共有することによって , 少な 数のモジュールがメモリの同じ部 MS-C Ver. 6.0 の LINK は , 複 ロードされます。 必要になったときにだけメモリに プログラム中のコードの一部は , る処理を行う方法て、す。この場合 , メモリ上て、 , 大量のメモリを要す 分を共有することによって少ない オーバレイは , メモリの同じ部 オーノヾレイとは MS-C Ver. 6. O メモリモテル オーバレイが使えるのは , ミデ イアム , ラージ , ヒュージモデル プログラムだけてす。スモールお よびコンパクトモデルプログラム て、は , 異なるモジュールのコード はひとつのセグメント ( C て、は TE XT セグメント ) に置かれます。 ディアム , ラージ , ヒューシモデ ルて、は , 各モジュールは独自のセ グメントを定義します。オーバレ イを機能させるためには , 別々の セグメント名が必要て、す。 ! オーノヾレイの指定 オーバレイを指定するには , 複 数のオプジェクトファイル名をカ ッコて、囲んて、指定します。カッコ て、囲まれたオプジェクトファイル のグループは , ひとつのオーバレ イを表します。たとえば , LINK コ マンドラインの < objfiles > フィー ルドに , Fig. 2 のようにオプジェク トファイル ( ライプラリも可能 ) の リストを指定します。 Fig. 2 の例て、は , モジュール ( b 十 c), (e 十 f), および ( i ) がオーバレ イて、す。残りのモジュール ( a と g), および <libraries> フィールド のライプラリからのモジュールは , プログラムの実行中ずっとメモリ に常駐したままとなります。ま た , <objfiles> フィールドに指定 されたライプラリも , オーバレイ

3. 月刊 C MAGAZINE 1992年6月号

アルゴリズム 0 テータ構造入門 List 1 86 : 88 : 89 : 92 : 93 : 94 : 95 : 96 : 98 : 99 : 100 : 101 : 102 : 103 : 104 : 105 : 106 : 107 : 108 : 109 : 110 : 111 : 112 : 113 : 114 : 115 : 116 : 117 : 118 : 119 : 120 : 121 : 122 : 123 : 124 : 125 : 126 : 127 : 128 : } cache t *p; FILE *fp; / * すでにそのファイルがオープンされているかチェックする。 for (p = cache list. next; p ! = &cache list; P = p->next) ェントリをキャッシュリストの末尾に移動する。 / * このファイルはすでにオープンされていた。 ニの { if (strcmp(filename, p->filename) / * リストの先頭のキャッシュエントリを取り出して , return p—>fp; insert_cache(&cache 1 ist, P) ; remove_cache ( p) ; cache hit + + ; printf("Cache hit ” , filename); return NULL; ニ NULL) if (fp fp = fopen(filename, "a") ; / * ファイルをアベンドモードでオープンする。 p->fp ニ NULL; fclose(p->fp); printf("CIosing [Xs]*n", p->fi lename) : if (p->fp ! = NULL) { / * もとのファイルをクローズする。 * / insert_cache(&cache 1 ist, p) ; p = remove cache(cache 1 ist. next) ; リストの末尾に移動する。 * / / * キャッシュにファイル記述子とファイル名をセットする。 再度 open ー f ⅱ e を呼び出すと無効になる例 return fp; cache missed 十十 : strcpy()- 〉 filename, fi lename) ; p->fp = fp; printf( ” 0pening [Xs]*n", fi lename) : List 2 1 : 2 : 3 : 4 : 5 : fp0 ニ open—fi le ( " f00 ” ) : fprintf(fp0, ” This is f00 file. fpl = open—fi le("bar ” ) : fprintf(fp0, ” This is f00 file. yn"); fprintf(fpl, ” This is bar file. 14 行て、定義されているマクロ定数 FILEN AME LEN はファイル名の最大長て、す。 18 行のマクロ定数 CACHE SIZE は , キャッシ ュするファイル記述子の個数て、す。これは , 同時にオープンて、きるファイルの個数以下 て、なければなりません。 21 ~ 28 行は , キャッシュのエントリを表 す cache t 型の定義て、す。ファイル名 filena me, ( オープンされた ) ファイル記述子 fp , 双方向リストて、の前の要素へのポインタ pr ev, 次の要素へのポインタ next の四つのメ ンバから成る構造体になっています。メン バ fp に NULL がセットされていると , その 工ントリは使われていないことを表します。 初期化するときに , NULL をセットしてお きます。 31 行の配列 cache がキャッシュの実 体て、 , 34 行の変数 cache list がキャッシュを 管理する待ち行列を表すリストの頭て、す。 関数 insert cache は双方向リストへの挿 入 , 関数 remove cache は双方向リストから の削除を行います。このふたつの関数を用 いて , 待ち行列を管理します。 関数 init cache は , 初期化を行います。す べてのキャッシュを侍ち行列を表す双方向 リストに登録します。関数 end cache は , キ ャッシュに含まれるオープンされているす べてのファイルをクローズします。 関数叩 en file が実際の仕事を行う関数 て、 , ファイル名を表すパラメータ filename を受け取って , それに対応するファイル記 述子を返します。まず , 90 ~ 102 行の for ルー プて、 , すて、にそのファイルがオープンされ てキャッシュに登録されているかどうかを 調べます。もし見つかれば , そのエントリ を待ち行列の末尾に移動して , メンバ fp に含 まれるファイル記述子を戻り値として retur n します。 もしそのファイルがオープンされていな ければ , 106 行以降が実行されます。 106 行 て、待ち行列の先頭のキャッシュエントリを 末尾に移動しています。また , ポインタ p に はこのエントリへのポインタをセットしま す。 次に 111 ~ 113 行て、 , そのエントリにセッ トされていたファイルをクローズします。 そして , ファイル filaname をアベンドモー ドて、オープンして ( 117 行 ) , 得られたファイ ル記述子とファイル名をキャッシュにセッ トします ( 123 , 124 行 ) 。最後にファイル記 述子を返します。 出力用ファイル記述子のキャッシングと いうアイデアは , 実際にはどの程度有効な のて、しようか ? それは , 叩 en file にケえられるファイル 名の傾向に大きく依存します。もし , ファ イル名の種類がのべ CACHE SIZE 以下だっ たら , すべてのファイルはキャッシュに収 まるのて、 , 1 回だけオープン / クローズされ ます。これは , すべてのファイルをあらか じめオープンしておくという方式と同じこ とになります。 すべてのファイル名が等しい確率て、完全 にランダムに与えられたとすると , キャッ シュはほとんど役に立ちません。最悪の場 合には , データの個数と同じ回数だけファ イルをオープン / クローズすることになるか もしれません。しかし , ファイル名の出現 頻度にかたよりがある場合には , キャッシ ュがうまく働き頻繁に使用されるファイル がキャッシュにとどまるようになり , ファ イルオープン / クローズの回数を大幅に減ら すことがて、きます。 アルゴリズムとデータ構造入門 67

4. 月刊 C MAGAZINE 1992年6月号

3647 て、すから , この方法は 2038 年 1 月 19 日に 破綻します。 新しい ANSI/ISO 規格て、は , time( ) 関数 の戻り値のために time t 型という新しい型を 設けて , time t は long と同義て、も , double か longdouble と同義て、もかまわない しました。時刻の原点も単位も自由に選ん て、かまいません。意味があるのは時刻の差 difftime(), a) だけて、す。 ちなみに , 時刻を求める関数には clock( ) というものもあります。これはそのプログ ラムの実行を開始してからの経過時間を返 します。引数はとらず , 戻り値は clock t 型 て、す。 clock( ) の返す値を秒に換算するに は clock( ) / CLOCKS PER SEC という割り算をします。 しかし , ANSI の委員会は最初 CLOCKS PER SEC を CLK TCK と呼んて、いたため , 規格の正式決定以前に出たコンパイラや本 には混乱が見られます。この CLOCKS PE R SEC の値は , PC ー 9801 系て、は 1 , IBM PC 系て、は 18.2 ( 正確には 1193180 / 65536 ) となっ ているのが普通てす。 LSI C ー 86 試食版ては 1 て、す。 なお , List 4b の考え方は PC-VAN の SH IMA さんに教えていただきました ( サイエン ス , 「計算機と算法」 # 6118 , 92 / 1 / 9 ) 。 SHIM A さんはこの考え方を OGATA さんという方 46 : } EXIT FAILURE E 刈 T SUCCESS たつの定数 て、エラーが出たら , プログラムの先頭に次 定数が定義されていないのて、 , コンパイル を使います。古いコンパイラて、はこれらの #define EXIT FAILURE 1 #define EXIT SUCCESS 0 の 2 行を補ってください る方法を示す簡単な例て、す。 #include く stdlib. h > は , たくさんの便利な関数の宣言や定数の 定義が書き込んて、ある <stdlib. h> ヘッダ をインクルードする命令て、す。このプログ ラムて、は , このヘッダて、定義されているふ 践 C プログラミング main ( ) から抜け出るとき , 今まて、は return 0 ; としていましたが , これからは return EXIT FAILURE ; return 0 ; return E 刈 T SUCCESS ; のようにします。 / * 失敗 * / / * 成功 * / return EXIT SUCCESS ; は という宣言があります。これは f という名前 FILE * f ; さて , プログラムて、は最初に と同じ意味て、す。 ファイルに読み書きする簡単な例 ( ⅱ st5. c ) Li st 1 : #include く stdio. h> 2 : #include く stdlib. h 〉 / * 入出力の準備 * / / * EXIT_SUCCESS, EXIT_FAILURE を使う * / 3 : 6 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 18 : 19 : 20 : 21 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : 38 : 39 : 40 : 41 : 42 : 43 : 44 : 45 : 4 : main( ) int r, c; FILE *f; / * ファイルポインタ f を作る * / / * 整数 (int 型 ) の変数 r, c を作る * / printf(" ファイル spock. txt を書き出し用に開きます . \ n ” ) ; fopen("spock. txt" / * w = write * / = NULL) { if (f ー / * 工ラーなら * / printf ( ”ファイルが開きません . \ n ” ) ; / * 実行を終了する * / return EXIT_FAILURE; pr intf ( " ファイルに何かしやれたことを書き込みます . }n" ) ; fprintf(), ” TO err is human. *n") ; / * ファイルに書き込む * / fprintf(f, ー Dr. Spock}n") ; / * ファイルに書き込む * / printf ( " ファイルの中身を表示します . \ n " ) ; return EXIT FAILURE; / * 実行を終了する * / printf ( ”ファイルが開きません . \ n " ) ; / * 工ラーなら * / if (f = NULL) { / * r ニ read * / fopen("spock. txt" printf( ”ファイル spock. txt を読み出し用に開きます . \ n " ) ; return EXIT FAILURE; / * 実行を終了する * / printf ( ”ファイルが閉じません . \ n " ) ; / * 工ラーなら * / if (r ! = の { r / * ファイルを閉じる * / = fclose(f); printf ( " ファイルを閉じます . \ n " ) ; から聞いたということて、す。 , ファイルに書き込む List 5 は , C 言語て、ファイルに読み書きす には , 別の方法を使わなければなりません。 くつものファイルを読み書きしたりする際 しかし , 読み書きを交互に行ったり , て、きます。 のようなリダイレクト機能を使えば簡単に program >file に書き込むには , 5 月号て、述べたように プログラムの出力を画面て、なくファイル while ( 1 ) { c = getc(f); = EOF) { / * 無限ループ * / / * 1 文字入力 * / / * 工ラーなら * / printf ( " ファイルが尽きました . \ n ” ) ; break; putchar(c) ; / * ループ脱出 * / / * 1 文字表示 * / printf ( ”ファイルを閉じます . \ n ” ) ; = fclose(f); / * ファイルを閉じる * / r if (r ! = の { / * 工ラーなら * / printf ( ”ファイルが閉じません . \ n ” ) ; return EXIT_FAILURE; return EXIT_SUCCESS; / * 実行を終了する * / / * 実行を終了する (return 0 ; と同じ ) * / 実践 C プログラミング入門 91

5. 月刊 C MAGAZINE 1992年6月号

出力ファイル記述子のキャッシュ (cache. c) す。まず , 関数 init cache はキャッシュのメ カニズムを初期化するためのものて、 , プロ グラムの開始時に必ず 1 回だけ呼び出す必要 があります。関数 end cache は , 終了処理を 行うものて、す。 関数叩 en ー file が本当の仕事をするための 関数て、す。叩 en file は , ファイル名を表す 文字列をパラメータとして受け取って , そ のファイルをアベンドモードて、出力用にオ ープンして , ファイル記述子を返します。 もし , 何らかの理由て、オープンに失敗する と NULL を返します。つまり , open file ( " f00 " ) List 1 2 : cache. C 4 : 5 : #include く stdio. h> 6 : #include く string. h> 7 : #include く ctype. h 〉 8 : 9 : int cache hit 10 : int cache missed = 0 ; 12 : 13 : / * ファイル名の長さ。 * / 14 : #define FILENAME_LEN 64 15 : 16 : なキャッシュされるファイルの数 ( 同時にオープンできるファイルの数以下でなければならない ) 17 : 18 : #define CACHE_SIZE 19 : 20 : / * キャッシュのエントリを表す型。 * / 21 : typedef struct cache { char fi Iename[FILENAME_LEN+1J ; 22 : 23 : FILE *fp; 24 : 25 : 26 : struct cache *prev; struct cache *next : 28 : } cache t; 29 : 30 : / * キャッシュの実体。 * / 31 : cache-t cacheCCACHE—SIZEJ ; 32 : 33 : / * キャッシュリストのヘッダ。 * / 34 : cache t cache 1 ist; 35 : 36 : / * p 。 s の直前に x を挿入する。 * / 37 : VOid insert_cache(cache_t *pos, cache t *X) 38 : { 39 : POS- 〉 prev->next ニ x; 40 : x->prev = pos—〉 prev; 41 : x- 〉 next : POS ; 42 : pos->prev : x; 44 : 45 : / * x を削除する。削除された要素 ( つまり x) を返す。 46 : cache_t *remove cache(cache t *x) 47 : { 48 : x ->prev- >ne xt x->next; 49 : x->next- 〉 prev = x->prev; 50 : return x; 51 : } 52 : 53 : / * 初期化処理を行う。 54 : プログラムの開始時に , 必ず 1 回だけ呼び出すこと。 55 : void init_cache() 56 : { 57 : illt i; 58 : / * キャッシュをリストに連結しておく。 59 : 60 : cache 1 ist. next cache list. prev = &cache list; for (i = 0 ; i く CACHE-SIZE; i + + ) { 61 : cacheCi]. fp ニ NULL; 62 : insert—cache(&cache list, &cacheCi)) ; 63 : 64 : 66 : 67 : / * 終了処理を行う。 プログラムの終了時に , 呼び出すこと。 68 : 69 : void end—cache() 70 : { 71 : int i; 72 : 76 : 77 : 78 : } 79 : 80 : / * ファイル f i lename をアベンドモードでオープンして , ファイル記述子を返す。 81 : ファイルが存在しなければ , 新規に作成する。 82 : ファイルのオープンに失敗したら NU LL を返す。 * / 83 : 84 : FILE *open_file(char *filename) ー出力用ファイルをキャッシュする。 10 / * ファイル名。 * / / * ファイル記述子。 ( NULL なら , このエントリは未使用 である。 ) * / / * 前の要素を指す。 * / / * 次の要素を指す。 * / は fopen ( " f00 " と同じ作用を持ちます。 ただし , open file が返すファイル記述子 は , 再び叩 en file を呼び出すと無効になっ てしまうことに注意しましよう。なぜなら , open file が , すて、にオープンされているフ ァイルをクローズする可能性があるからて、 す。たとえば , List 2 のようなプログラムが あったとします。 1 行目て、得られたファイル 己述子 fp0 が有効なのは 2 行目まて、て、す。な ぜなら , 3 行目の叩 en file の呼び出して、 fP0 がクローズされる可能性があるからて、す ( も ちろん , クローズされない可能性もありま す。しかし , クローズされるかどうかは予 測不可能て、す ) 。て、すから , 4 行目の fprintf て、 fp0 を参照しているのは誤りて、す。また , 関数 open file て、得られたファイルは fclose を する必要はありません。 open file て、オープ ンしたファイルは , 以降の open file の呼び 出しか ,end cache の呼び出しによってクロ ーズされます。 List 1 のプログラムを追いながら説明しま しよう。 9 , 10 行て、定義されているふたつの グローノヾル変数 cache hit と cache missed は , open file の呼び出しのうち , キャッシ ュにヒットした回数 , ヒットしなかった回 数をカウントするカウンタて、す。これらの 変数は , プログラムの動作の統計をとるた めだけのものて、す。プログラムの動作には 何の意味もありません。 66 C MAGAZINE 1 2 6 一三ロ / * オープンされているファイルをすべてクローズする。 for (i = 0 ; i く CACHE_SIZE; i + + ) ( if (cache[i). fp ! : NULL) fclose(cacheCi]. fp);

6. 月刊 C MAGAZINE 1992年6月号

アルゴリズム 0 テータ構造入門 ロックアドレス 113 ) に含まれるのて、 , その プロックをバッフアに読み込みます。そし て , そのノヾッフアの 476 ~ 495 バイト目の 20 バイトをユーザが指定した領域にコピーし ます。 また複数のプロックにまたがる場合には , この手順を繰り返し行うことになります。 ファイルの先頭から 800 バイト目から 2299 バ イト目の合計 1500 バイトを読み込む例を Fi g. 4 に示しましよう。 書き込みの手順は , 読み出しの手順とほ とんど同じて、す。しかし , そのプロックを あらかじめバッフアに読み込んて、から , バ ッファ ~ 書き込むデータをコピーして , 最 後にプロックをディスクに書き戻すという 3 段階の手順が必要になります。 こて、は , ファイ Fig. 5 を見てください ルの先頭から 1500 バイト目から 20 バイト分 のデータを書き込もうとしています。まず 最初に , 1 番目のプロック ( プロックアドレ ス 113 ) を丸ごとバッフアへ読み込みます (F ig. 5 ー① ) 。次に , 与・えられた 20 バイトのデ ータをバッフアの所定の位置 ( 476 ~ 495 バイ トめ ) にコピーします (Fig. 5 ー② ) 。そして , バッフアの内容をプロックアドレ 最後に ス 113 に書き戻します ( Fig. 5 ー③ ) 。 こて、 , 1 番目のプロックに含まれていて , 書き込み が行われない部分 ( Fig. 5 ー②の横線を引いた 部分 ) の値を保存するために , あらかじめプ ロックをバッフアに読み込まなければなら ないことに注意しましよう。もし , Fig. 5 ー ①の手順を省いてしまうと , この部分にゴ ミのデータが書き込まれてしまうことにな ります。もちろん , 1 プロック分をまるごと 書き込む場合には , Fig. 5- ①の処理は不要 て、す。 バッファリングという技法 このように を用いれば , 本来ならプロック単位て、しか 読み書きがて、きないプロックデバイスても バイト単位て、の読み書きが可能になります。 ティスクのキャッシンク、 ところて、 , 今まて、に説明した方式て、は , 読み書きの要求があるごとに ノヾッフア領 域とディスクの間て、必ず 1 回はデータを転送 する必要があります。しかし , 実際には , ファイルへの読み書きは , 連続した位置に 対して行われるのが普通て、 , この場合には , 同じプロックを何度も繰り返し読み込むこ とになります。 たとえば , Fig. 2 のファイルを 512 バイト ずっ順番に読み込んて、いくことを考えまし よう (Fig. 6 ) 。この場合には , まず先頭のプ ロックをバッフアに読み込んて、 , その前半 512 バイトをユーザの指定した領域にコヒ。ー します (Fig. 6 ー① ) 。次に , 再び先頭のプロ Fig. 5 ファイルへの書き込みファイルの 1500 ノヾイト 目から 20 バイト分のテータを書き込む 52 24 25 113 ファイル 八ッファ 書き込む ① 1 番目のプロックをバッフアに読み込む 47 47 ファイル バッファ 書き込む テータ コピーする ファイル 八ッファ 52 113 24 25 書き込むテータをバッフア内の所定の位置 ( 476 ~ 495 バイト目 ) に 52 113 24 25 47 書き込む ③バッフアの内容を 1 番目のプロックに書き込む ファイルの読み込み時のムダなティスク入力の回避 ファイル ↓ バッファ ユーザが指 定した領域 ①先頭のプロックをバッフアに読み込んでから前半の 512 バイトを 指定された領域にコピーする ↓ ファイル ↓ バッファ ユーサが指 定した領域 再び先頭のプロックをバッフアに読み込んて後半の 512 バイトを コピーする ファイル バッファ ユーザが指 定した領域 ③すでに先頭のフロックがノヾッフアに読み込まれている バッフアの後半 512 バイトをコピーする アルゴリズムとデータ構造入門 63

7. 月刊 C MAGAZINE 1992年6月号

ャラクタデバイスかの区別 ) を , プログラム が意識する必要はありません。また , 反対に いえば , このようにソフトウェアから見た I / O 装置の扱いが統一されているからこそ , 入出力のリダイレクトやパイプラインがサ ポートて、きるのて、す。 プロックデバイスから , 任意の長さのデ ータを読み出すことを考えましよう。前回 , 少し触れたようにプロックデバイスを扱う 場合 , ファイルはプロック単位て、割り当て が行われます。たとえ大きさが 1 バイトのフ ァイルて、も , ディスク上て、はまるまる 1 プロ こて、は , 1 プロックの ックを占有します。 大きさがちょうど IK バイト ( 1024 バイト ) に なっているものとして話を進めましよう。 ファイルはプロックの集まりとして表現 されます。また , ディスク上のプロックに は , プロック番号が振られています。プロ ックの読み書きは , プロック番号 ( または , CPU Fig. 1 キャッシュメモリ プロックアドレスともいう ) を指定して行い ます ( 実際には , ディスクのアクセスは , シ リンダ番号 , ヘッド番号 , セクタ番号を指 定して行いますが , 話を単純にするために プロック番号て、プロックの指定を行うこと にします ) 。 Fig. 2 のようにプロックを割り当てたファ イルを考えてみましよう。先頭から順に プロック番号が 52 , 113 , 24 , 25 , 47 , 18 に なっています。ファイルの先頭から 1023 バ イト目まて、はプロック番号 52 に , 1024 ~ 20 47 バイト目はプロック番号 113 に , 2048 ~ 3 071 バイト目まてはプロック番号 24 に , とい う具合に対応しています。一般に先頭から k バイト目のデータは , k / 1024 番目のプロッ ク ( ただし , 小数点以下は切り捨て ) の先頭 から k% 1024 バイト目に位置します。 て、 , 先頭のプロックは 0 番目として数えてい ることに注意してください。たとえば , 15 00 バイト目のデータは , 1 番目のプロック (Fig. 2 て、いえば , プロック番号が 113 ) の 47 6 バイト目に対応しています。 基本的には , 目的のデータが含まれるプ ロックを読み込んて、 , そのうちに実際に必 要になる部分だけを読み込み領域にコヒ。ー するという方針て、いきます。 こて、 , 読み 込みはプロック単位てしか実行て、きません から , 1 プロック分のデータが入るだけの / ヾ ッファ ( 作業領域 ) を用意しておいて , ディ スクからプロック長のデータをノヾッフアに 読み込んて、から , そのうちの指定されたバ イトだけをユーザが指定した領域にコピー します。これをバッファリング ( bufferring ) といいます。 例として , ファイルの先頭から 1500 バイ ト目から 20 バイトを読み出すことを考えて みましよう (Fig. 3 ) 。 1500 バイト目のデータ は , 先ほど見たように 1 番目のプロック ( プ Fig. 4 複数のフ、ロックにまたがる読み込み ファイルの 800 バイト目から 1500 ノヾイトを読み込む CPU アクセス時間 30nsec 52 113 24 25 47 ファイル ↓ 18 キャッシュメモリ アクセス時間 60nsec アクセス時間 60nsec メモリ メモリ (a) キャッシュメモリなしのシステム (b) キャッシュメモリつきのシステム Fig. 2 ファイルのプロック割り当て 0 1024 2048 3072 4096 5120 6144 52 0 113 1 24 2 2 5 3 24 47 4 25 ( バイト ) ( プロック ) Fig. 3 ファイルの読み込み 5 47 ファイル バッファ ユーザが 指定した 領域 62 C MAGAZINE 52 113 1992 6 ・ファイルの 1500 ノヾイト目から 20 バイト読み込む バッファ ユーザか 指定した 領域 ① 0 番目のプロックをバッフアに読み込み , バッフアの 800 ~ 1023 ノヾイ ト目をコピーする ファイル 2 5 52 24 47 113 八ッファ ユーサが指 定した領域 をコピーする ③ 2 番目のプロックをバッフアに読み込み , バッフアの 0 ~ 251 八イト目 定した領域 ユーサが指 バッファ 113 47 2 5 24 52 ファイル 01 番目のプロックをノヾッフアに読み込み , バッフア全体をコピーする

8. 月刊 C MAGAZINE 1992年6月号

立見ト 新環一 最発ポ 丹羽信夫 『 C まつぶ』 「 C まつぶ」は C 言語使用のアプリケーション開発 支援 , およびドキュメント作成のたユーティ リティである。 「 C まつぶ」は , 与えられた C ソースファイ アップして表示。 ーしめに ル群の関数定義内容や , ソースファイルの依 ある関数が他関数から使用されている状況 存関係 , ある関数の他関数からの呼び出し を表示。あるいは逆に , その関数が使用して C 言語を使ってアプリケーションを作成す ( 呼び出され ) 状況 , 逆に他関数の呼び出し状 いる他関数名を表示。 る場合 ( C て、なくても同じようなものだが ) , 指定関数がどのような流れに従ってプログ 況などを整理しメンテナンス資料を作成した 複数 ( あるいは多数 ) のソースファイルにプロ り , 関数仕様書などのドキュメント類をお手 ラムされているのか , 使用されている順にプ グラムを分割して記述するのが普通て、ある。 軽に作成してくれる便利なユーティリティて、 ログラムリストを表示。その際 , TAB コー アプリケーションを作成しているときは記 ドを指定数のスペースに置換して表示する。 ある。 憶も鮮明て、 , C のソースファイルやインクル 各ソースファイル内の定義関数名 , 型 , ソ !@ま。ぶ」の機能 ードファイル , オプジェクトファイルの相互 ース内の位置を表示する。 関係などのほかに , ソースファイル中の各関 ソースファイル内の関連関数を表示する。 数の動作や返り値 , 引数の意味 , 変数の内容 ソース内に表われた関数名にカーソルをあわ 「 C まつぶ」の機能は非常に豊富だ。おもな せ , ーキーを押すと , その関数の定義 などを記憶保持しているかもしれないが , 日 機能を紹介する。 がたつにつれて記憶もうすれ , いざ仕様変 タイムスタンプチェックなどによるファイ 部分に飛ぶ。そこて、十一キーを 更 , やれバグへの対応などというときに , プ ルコヒ。ー機能。更新したファイルのみをコピ 押すと , その関数が使用されている関数に飛 ログラムの流れを追うことさえて、きない状況 ーする機能がついている。 ぶことがて、きる。ソースの内容を見ながら流 作成した各種のドキュメントは CRT に出力 になっていたりして冷汗をかいたことが , 皆 れを確認て、きるわけだ。 こういう場合て、 するもの , プリンタに出力するもの , ファイ 定義関数仕様書の作成。定義された関数名 さんはなかっただろうか ? などを印字するのて、 , 返り値などを手書きて、 も , 自分て、作成したソースなら徐々に記憶も ルに出力するものがそれぞれ用意されてい よみがえるかもしれないが他人の書いたプロ 記入する。仕様書のための雛形作成機能て、あ グラムを解読しなければならないときなど 定義関数の構成図を作成する (Fig. 1 ) 。ど る。定義された関数全部に対して行う方法と は , そもそもの記憶が存在しないのだから , 指定関数に関連する関数を自動的にピックア のような関数によってその関数が構成されて さらにたいへんて、ある。 いるかを , 構成する関数が存在するファイル ップして行う方法とがある。 これらの障害は , ドキュメントを完備して 名とともに表示する。 ソースファイル , ヘッダファイルに定義さ おけば , かなりの部分は解決する。しかし , 定義関数のプロックチャート図を作成する れた変数の内容をファイル出力。 ご存じのとおり , ドキュメント作成はやたら あるラベルがどのソースファイルて、定義さ (Fig. 2)0if による条件分岐や for によるルー にめんどうに思える作業て、ある ( デバッグに れているのか , またどの関数て、使用されてい プなどによるプログラムの流れを把握て、き 追われて , ドキュメントを書くための物理的 る , いわゆる流れ図を表示て、きる。 るのかをまとめて出力。 DEFINE, 外部変 時間が残り少なくなってしまうのも困ったも 関数のうち , 使用されているもの , 定義だ 数 , そのほかに分類しアルファベット順に出 けて、まったく使用されていないものをリスト 力。定義情報だけを出力する方法と , ラベル のだ ) 。 138 C MAGAZIN E 1992 6

9. 月刊 C MAGAZINE 1992年6月号

lnformation from Compiler Makers に含めることがて、きます。 オーノヾレイマネージャのコード は , 標準ライプラリに含まれてい て , LINK コマンドライン上て、オー バレイ指定がされると , オーバレ イマネージャは自動的にほかのモ ジュールとリンクされます。また , オーバレイの中のルーチンへの far コールは ( 後にモジュール識別子と オフセットが続く ) 割り込みに置き 換えられます。デフォルトの割り 込み番号は 63 ( 0x3F ) て、す。この割 り込み番号を変更するには , / O オ プションを使います。 オーバレイはメモリの同じ場所 にロードされるのて、 , 1 回にひとつ のオーバレイしかメモリ上に存在 て、きません。異なるオーバレイに 同じ名前のモジュールがあっては いけません。ひとつのプログラム の中て、 , 各モジュールは 1 回しか現 れません。 オーノヾレイモジュール オーバレイを使う場合て、も , LI NK はひとつの . EXE ファイルしか 作成しません。このファイルは , オーバレイモジュールが必要とな るたびに , 繰り返し読み込まれま す。 実行ファイルが実行されると , オーバレイマネージャは , 別のオ ーバレイモジュールをロードする 必要が生じるたびに , この . EXE フ ァイルをサーチします。 オーバレイマネージャは , 最初 にカレントディレクトリを探しま す。該当するファイルを発見て、き ない場合は , PATH 環境変数て、設 定されているディレクトリを探し ます。それても発見てきなければ , ファイル名の入力を要求するプロ ンプトを表示します。たとえば , オーバレイを使う実行ファイル PA YROLL. EXE が , カレントディレ クトリにも , PATH て、設定されて いるディレクトリにも存在しない とします。この場合 (PAYROLL. E XE が存在するディレクトリ以外か ら , フルバスを指定して ) PAYRO LL. EXE を実行すると , オーバレイ ファイルをロードしようとした時 点て、 , オーバレイマネージャが Fi g. 3 のようなメッセージを表示しま す。 プログラムの実行を続けるには , こて、 , PAYROLL. EXE が存在す る場所を示すドライプ , またはデ ィレクトリ , あるいはその両方を 入力します。たとえば , このファ イルが B : YEMPLOYEEYDAT AY にある場合 , B : *EMPLOYEE*DATA* と入力するか , カレントドライプ が B なら , 単に YEMPLOYEEYDA TAY と入力します。 その後 , ドライプ B からディスク を取り外し , オーバレイマネージ ャが再びオーバレイをアクセスす る必要が生じた場合は , Fig. 4 のよ うなメッセージが表示されます。 オーノヾレイファイルがディスク から読み込まれると , オーバレイ マネージャは Fig. 5 のようなメッセ ージを表示します。 オーバレイプログラム 作成上の注意 ・プログラムによっては , オーバ レイを使用て、きない場合もあり ます。 ・ MS-DOS Ver. 2.11 以前て、は , オーバレイを含む実行可能プロ グラムファイルをリネームしな いて、ください 0LINK は , プログ ラムファイルに . EXE ファイル名 を記録します。ファイル名を変 更すると , オーバレイマネージ ャが正しいファイルを探せなく なります 0MS-DOS Ver. 3.1 以 降て、実行する場合はリネーム可 能て、す。 ・オーバレイされるモジュール間 て、制御を移すには , far コール / リ ターン命令を使わなければなり ません。ほかのモジュールがこ れらのルーチンを呼び出す場合 は , near ルーチンを含むモジュ ールをオーバレイすることはて、 きません。 ・オーバレイされるモジュールて、 は , longjmp ライプラリ関数を使 ってモジュールを出る , または モジュールに入ることはて、きま せん。ただしモジュール内て、あ れば可能て、す。 ・関数ポインタを使って , オーバ レイされるモジュールを出る , または入るルーチンを呼び出す ことはて、きません。ただしモジ ュール内て、あれば可能て、す。 一度にひとつのオーバレイしか 必要ないように , プログラムを 構成しなければなりません。 ・異なるオーバレイて、 , 同じパプ リック名を使うことはて、きませ ん。 Fig. 2 Fig. 4 Fig. 3 Fig. 5 オーバレイの指定 ( 凵 NK のく objf ⅱ es > フィールド ) a 十 (b 十 c) + (e + f) + 9 十 (i) オーバレイマネージャのメッセージ ( 2 ) Please insert diskette containing オーバレイマネージャのメッセージ ( 1 ) Cannot find PAYROLL. EXE Please enter new p 「 ogram spec ・ lnformation from Compiler Makers 149 Strike any key when ready. Please restore the original diskette. オーノヾレイマネージャのメッセージ ( 3 ) and strike any key when ready. B : *EMPLOYEE*DATA*PAYROLL. EXE in drive B .

10. 月刊 C MAGAZINE 1992年6月号

' 92 年 6 月号特別付録 ( 5 ク 1.2M8 セクタ / ト よび patch5 てパッチあて変更済みファイル は , 「 Logomotion 」が , なぜ ? どのように ラック MS ー DOS フォーマット ) には , 次のプ て、す。 して作られたのかを本誌て、はなかなか味わ ログラムが収録されています。 付録ディスクに収録した えない軽妙なタッチて、記述されています ) 。 ①付録ディスクの説明 *DJUP*PATCH45B. EXE 付録ディスクに収録した ( テキストファイル ) は自動解凍圧縮ファイルて、す。解凍後生成 README *LOGOM*LOGOM. EXE ② djgcc バージョンアップ対応 されるファイルを適正なディレクトリにコ は自動解凍圧縮ファイルて、す。解凍後生成 変更ファイル ( その 2 ) ヒ。ーしてください される README をご一読のうえお楽しみく < ディレクトリ > YDJ UP NEC A 仂、な漢字変換 ③ NEC AI かな漢字変換 カスタマイズユーティリティ 本誌掲載プログラム カスタマイズユーティリティ くディレクトリ > YAICFG 日本電気純正の日本語入力 FEP に不満を ④ LOGO インタブリタ「 Logomotion 」 抱き使用することをあきらめている方や他 : C 十十てエラー表示を楽に ERROR YLOGOM くディレクトリ > の FEP を持っていないのて、しかたなく使っ : 速報 98 版 BORLAND C 十十 BCPP ⑤本誌掲載プログラム ている方などにうってつけのユーティリテ : 特集第 3 の標準 , JIS C 概観 TOKUSYU ィて、す。この NECAI かな漢字変換カスタマ YCMAGA くディレクトリ > ESSEN CE : プログラミングの工ッセンス ⑥ READ. ME 参照ューティリティ イズユーティリティは , 日本電気の MS ー DO : アルゴリズムとデータ構造 ALGO README. EXE ( 実行ファイル ) S3.3C 以降に付属している AI かな漢字変換 MSDOS : 新 MS-DOS 入門 付録ディスクの説明 (README) に , 解凍 にパッチを当てることによって初期設定や STEPC : 実践 C プログラミング入門 方法など , さらに詳しい説明が収録してあ 表示色 , 操作キーなどのカスタマイズを可 : 恥ずかしながらドジりました DOJI ります。必ずご一読ください 能にするプログラムてす。詳しくは本誌掲 : ANSI C ー more ANSI README はテキストファイル形式てす。 載記事「日本電気純正 FEP 「 AI かな漢字変 : 応用 C 言語 C の道具箱 OUYOU 本誌付録ディスク収録の README プログラ 換」の内部を探る』に譲ります 0NECAI かな : X68k 活用講座 X68K 漢字変換カスタマイズユーティリティは , A : あつばれご意見番 ム , MS-I)()S の TYPE コマンド , あるいは APPARE ご使用のエデイタ , ワープロソフトて読む ICFG ディレクトリに収録しました 0READ : C マガ電脳クラブ PUZZLE ことがて、きます。 ME. DOC に配付パッケージ内容一覧が , NE : 迷走プログラミング NIWA CAICFG. DOC に利用方法などの解説が明記 INFO : インフォメーション dJgcc バージョンアップ対応 されています 0README. DOC および NEC おのおののプログラムについては , 関連 変更ファイル ( その 2 ) AICFG. DOC をご一読のうえご利用ください 記事と各ディレクトリの README を参照く 好評連載中「 djgcc 詳解講座 He110 GCC ださい LOGO インタブリタ WorId 』において再三紹介してきた djgcc の 「 Logomotion 」 日 EAD. ME 参照ユーティリティ patch4 と patch5 両方の変更点を含む変更フ ( DOS マシン対応 ) 本誌 ' 92 年 3 月号「フリーソフトウェア最新 ァイルて、す。 , 91 年 10 月号および ' 92 年 1 月号 レポート」て紹介した「 Logom 。 tion 」て、す。 ' 92 年 4 月号「新 MS ー DOS プログラミング て配布したファイルをインストールしたデ この「 Logomotion 」はユニー株の 3D ー LOGO 入門」て、紹介した READ. ME 参照ューティリ ィレクトリに , 今回および前回収録したフ と同様の 3 次元タートルグラフィックをサポ ティ ( テキストファイルを画面上て読むプロ ァイルを解凍し生成されるファイルて置き ートしている LOGO 言語のサプセットのイン 換えるだけてバージョン 1.03 から 1.05 へバ グラム ) の実行ファイル ( README. EXE ) を タブリタてす。もちろん本家の 3D ー LOGO に ージョンアップてきます ( PC ー 9801 てご使用 README と同じルートディレクトリに収録 は遠く及びませんが , 楽しいデモプログラ しました。付録ディスクをセットしたドラ されている方は 4 月号て、収録した 98 パッチも ムは皆さんのアイデアしだい。東京女子大 イプにカレントを移し 必要てす ) 。 学の学生さんに負けないようデモプログラ なお , オリジナルは patch4. zip と patch README@ ムに挑戦してください ( 解凍後生成される R て README ファイルが画面に表示されま 5. zip という別々のファイルて配布されてい EADME の開発経緯を参照。この開発経緯 ます力℃マガジンて配布するものは patch4 お す。お試しください ディスク内容のおしらせ 159