関数 - みる会図書館


検索対象: 月刊 C MAGAZINE 1989年12月号
87件見つかりました。

1. 月刊 C MAGAZINE 1989年12月号

execve( ) execv( ) execvpe( ) spawnlpe( ) spawnv( ) spawnve( ) spawnle( ) spawnlp( ) spawnl( ) spawn 系の 8 関数すべて spawnvp( ) spawnvpe( ) そのほか system( ) exit( ) exit( ) [ 表 1 ] exec 系関数とその仕様 く p rocess.h 〉 execlpe( ) execvp( ) (char *path, (char * ath, (qhar *path, (char * path, (char *path, 1 : = %s Yn ” abort( ) ・ exec 系関数 exec 系の関数は子プロセスを起動させる ときに , 自分自身のプロセスにオーバレイ を行う機能をもっている。プロセスを生成 する , または起動させるほうのプロセスを 親プロセスといい , 生成または起動された ほうのプロセスを子プロセスと呼ぶことに NULL, char * *envp); , NULL, char * *envp); , NULL); する。一度て、も起動された子プロセスから 親プロセスに戻ることはない。しいていう なら , 子プロセスの終了は COMMAND. COM に戻ることになる。もちろん使い方に もよるが , メモリの効率を考えるとこのオ ーバレイ機能はぜひ必要て、あろう。だが , メモリが安価に手に入る現在ては , メモリ をふんだんに使う傾向にある。 ところて、 , exec 系関数には , exec の文字 列の後に次の文字のいずれかが複数付加さ れているはずて、ある。それぞれの文字には 次のような意味がある。 int int int int int int List 1 execl execle int execlp int execlpe execv execve execvp ex ecvpe (char (char (char *path, *path, * path, char char char Char char Char char char * argO, *argO, * argO, * argO, *argv ロ ) ; *argv [ ] , char * *envp); * argv ロ ) ; * argv [ ] , char * *envp); exec. c 系関数とその仕様 Cp] [ 1 ] [ ⅵ 2 : 3 : 4 : 7 : 9 : 12 : 13 : 14 : 1 : #include く stdio. h 〉 #include く process. h 〉 v 0 i d ma i n ( ) printf("exec running if( execl ("A:YYwork"chiId1. pr intf ( " E X E C 関数がうまく動きません . Yn" ) : exe " 123 " , " 456 " , " 789 " , NUL し ) ニー 指定ファイルを探すために SET コマ ンドによって指定されたパスを検索 する。この文字が付加されていない 場合は , カレントディレクトリだけ を検索する。 子プロセスに直接渡したい値を個別 に引数として与える。一般に引数の 個数がわかっているときに使用する。 子プロセスに直接に渡したい値を文 字列のポインタとして与える。一般 に引数の個数が可変のときに使用。 子プロセスに環境変数を引き渡す。 この文字が付いた exec 関数は , 子プ ロセスの環境変数を変えることがて きる。 Ce] がない場合は , 親の環境 をそのまま引き継ぐ。 ex i t ( 1) : printf("exec stopped childl . c List 2 #include く stdio. h> 2 : 3 : 5 : 6 : 7 : 8 : 9 : int main(int argc, char *argv[]) i nt i : printf("child process running . for(i i く argc printf ( ” argc argv C%d] 1 , argv[i]): このときに注意することがいくつかある。 第 1 に , 親プロセスがオープンしているファ イルは基本的に引き継ぎされないというこ とて、ある。これは , 親プロセスと子プロセ スの基本関係は別個のものと考える必要が のため , MS ー DOS Ver. 3.1 と MS ー C DOS だけて、なく , MS ー C にもバグがある。そ めする。だが実際のところ , おそらく MS- Ver. 3. xx 以降において使用することをお勧 ある。このため , これらの関数については , 重大なシステムエラーを引き起こすことが Ver. 2.11 ては , exec 系関数にバグがあり , すいためてもある。第 2 に , MS ー DOS あるためて、あり , またそのほうが処理しや 64 CMAGAZINE 1989 12

2. 月刊 C MAGAZINE 1989年12月号

本型や , それらからっくられた派生型をさ 値を返さない関数の場合には , void を使 のように int と long の大きさが異なる場合 には , これは正しく動かないプログラムと らに加工するときに使います。派生型には って宣言します。 void は「無効」という意味 配列 , 関数 , ポインタ , 構造体・共用体が て、 , 「この関数の返す値は使ってはいけない」 いうことになります。正しくは , あります。て、は , これらについて説明して というニュアンスて、しようか。 fseek(fd, IOL , 0 ) ; いきましよう。 void func( ) ; のようにパラメータが long て、あることをコ ( ) の中には , その関数のパラメータを書 ンパイラに明示的に伝える必要があります。 配列 くことがて、きます。たとえば , ふたつの int これに対して , プロトタイプ宣言をして C て、は「任意の型の配列は型て、ある」と決め 型のパラメータをもらって , そのうちの大 いる場合は , 10 は正しく long に変換されて られています。配列を表すのに口を使う から fseek に渡されます。このように自動 きいほうを返す関数 max は のはご存じのとおりて、す。ロの中には定数 的な型変換機能がないために , デバッグに int max(int x, int y) ; を書いて , 配列の大きさを指定します。 のようにして宣言してやることがて、きます。 苦労した人も多いのて、はないて、しようか ? char arrayt10] : このように ところて、 , パラメータをとらない関数の ノヾラメータを含めて宣言する という宣言は , array が char 型の 10 個の要 場合には , ( ) の中に void と書きます。ただ ことを , 関数のプロトタイプ宣言といいま 素をもっ配列て、あることを示しています。 す。プロトタイプ宣言は , ANSI 規格案に含 ( ) と書くと , 「その関数はパラメータのチェ 配列の名前 array は ,array が占有するメ ックはしなくていいよ」という意味になり , まれていて , 最近の C コンパイラはほとん モリ領域の先頭番地を表します。 ANSI 規格案以前のコンパイラと同じ動作に どがサポートしています。また , 関数宣言 C の配列の添字は 0 から始まります。した のときにはパラメータの変数名は省略て、き なります。 がって , N 個の要素をもつ配列の添字の範 int f(void) ; / * パラメータなし * / ます。つまり , 囲は 0 から N ー 1 まて、になります。 array [ 0 ] / * チェックしない * / int g( ) ; int max(int, int) ; から array [ 9 ] はたしかに確保した配列の と書いておけばいいわけて、す。 ポインタ 中になりますが , array [ 10 ] は配列の最後 プロトタイプ宣言の利点は , なんといっ の要素のさらに後ろになってしまいます。 ても関数の宣言と呼び出しの整合性をコン ポインタは * を使って , 「与えられた型の 確保していないメモリ領域をアクセスして パイラがチェックしてくれることと , 必要 アドレス」という型をつくります。 はいけませんね。 ならば型変換を実行してくれることて、す。 char * p ; さて , 2 次元配列は C て、は配列の配列とし 上記の max を呼び出すときに , パラメー はよく使いますね。 P は char 型のデータの アドレスを表しています op がメモリ上に占 て宣言します。 タを 3 っ渡してしまったり , ポインタを渡し char arrayC5]CIO) : める大きさは処理系によりますが , 変数 p の てしまったりすると , コンパイラが「宣言て、 指定したパラメータと , 実際に呼び出すと これは char 型の要素 10 個をひとつの配列 値はメモリ上のどこかにある char 型のデー とし , さらにそれが 5 個集まった配列を表し きのパラメータが一致していない / 」という タを指しています。 ています。多次元配列は「もっとも右側の添 アドレスの大きさがどのくらいのビット 工ラーを報告してくれます。これが整合性 字から変化していく」ようにメモリ上に割り のチェックて、す。 数て、表すことがて、きるかは , 各マシンによ 当てられることになっています。て、すから , さて , 標準ライプラリ関数の fseek ( ) をプ って異なります。一般的に int とポインタは メモリ上にはまず array [ O ] [ 0 ] が割り当て 相互に代入可能て、すが , 8086 の場合にはセ ロトタイプ宣言すると られ , 続いて arraYCO]C1] ・・・・・ arrayr.O] int fseek(int, long, int) ; グメントを考える必要があるため , ちょっ [ 9 ] , さらに arrayC1]C0] ・・ ・・というよう となります。プロトタイプ宣言を使用て、き とめんどうになります。 に割り当てられていきます。 ないコンパイラて、は 構造体・共用体 int fseek( ) ; 関数 て、す。ここて、 , プロトタイプ宣言をしてい 構造体・共用体は「いくっかの変数をひと 関数は宣言に ( ) をつけることによって指 つにまとめたもの」て、 , これも新しい型にな ないときに 定します。そして「その型を返す関数」とい fseek(fd, 10 , 0 ) ; ります。 う意味になります。たとえば という呼び出しがあったとすると , 第 2 パラ int func( ) ; メータの 10 は int 型として渡してしまいます。 struct という宣言は , func が「 int を返す関数」て、 ところが ,fseek は第 2 パラメータは long だ あることを示しています。 と思って処理しますから , 16 ビットマシン 124 CMAGAZINE 1989 12 int 1 ; long

3. 月刊 C MAGAZINE 1989年12月号

PART I 初級プログラミング編 uick C 2.0 徹底チェック 第 2 特集 いよいよ発売の QuickC Ve 「 .2 、 0 をチェックする。 ただし , C プログラマ向けに構成してあるので , 一般 的な機能については省くか , 簡単にしか触れていない。 池田和徳 また , 締切の関係で , メーカー提供の評価版でしかチ ェックできなかったことをお断りしておく。 機能て、ある。 デバッグ作業時に表示て、きるウインドウ テパッグ ◇変数変更 には以下のようなものがある。 Ver. 2.0 にしかない機能て、ある。デバッグ デパッグウインドウ現在実行中の関数 作業中に任意の変数に任意の値を代入て、き 名 , ウォッチ変数などを表示する Ver. 2.0 になって大幅に機能強化されたデ る機能て、ある。変数が特殊な値になった場 ヘルプウインドウヘルプ機能を呼び出 バッグ機能について , QuickC Ver. 1.1 およ 合の実行のシミュレーションなどを行うの びマイクロソフト社の CodeView と比較しな す に非常に有効な機能てある。 ローカル変数表示ウインドウローカル がら調べていきたい ◇ウインドウ 変数の内容を表示する 表 1 て、もわかるように , QuickC Ver. 2.0 Ver. 2.0 て、は画面をいくつかのウインドウ レジスタ表示ウインドウレジスタの内 のデバッグ機能はかなり強力て、ある。 に分割し各種の情報を表示て、きるようにな 容を表示する て、は Ver. 1.1 に比べて強化された点を中心 っている (Fig. 1 ) 。 ノートパッドウインドウメモに使う に見ていこう。 ◇ウォッチ [ 表 1 ] テパッグの機能比較一覧 デバッガの基本機能のひとって、ある。指 機能 QucikC Ver. 2 QuickC Ver. 1 CodeView 定した変数の内容を表示させることがて、き 変数 watch る。また表示する型 ( 文字列型 , 10 進型 , 16 resister local 進型など ) を指定することもて、きる。 変数変更 ◇レジスタ 表示画面 assembly window Ver. 2.0 になって追加された機能てある。 レジスタの内容を表示てきる。 ◇ローカル Ver. 2.0 にしかない機能てある。ローカル 変数をウォッチしたい場合 , CodeView ては 各関数内において個々にウォッチ式に設定 しなくてはならなかったが , Ver. 2.0 てはそ の必要がなくなった。 ローカル変数のウインドウをオープンし ておくだけて、 , 実行されている関数のロー カル変数が自動て、表示される非常に便利な 内容 指定した変数の内容を表示 レジスタの内容を表示 ローカル変数の内容を表示 指定した変数の値を変更 アセンプルリストを表示 ウインドウによる複数画面の表 1 行ずつ実行 trace 関数呼び出しをせずに 1 行ずつ ste p 実行 animate ゆっくりと実行 break point 指定した行で実行を停止 watch point 指定した変数が条件を満たした とき実行を中断 trace point 指定した変数の値が変化したと きに実行を中断 current line 現在行までの実行 history 実行履歴を覚えておく 現在の関数がどの関数から呼ば れているか表示 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 〇 各プログラムのテパック機能 ( 〇 : 可能 x : 不可能 ) 第 2 特集 QuickC ve 「 . 2.0 徹底チェック 79 〇〇 xx 〇 ><>< 〇〇〇〇〇〇〇〇〇 xx 〇〇 実行 関数 call

4. 月刊 C MAGAZINE 1989年12月号

ソースウインドウ 表示する。 工ラーウインドウ 工ラーを表示する。 ソースウインドウとの間て、切り貼りがてき るのて、使い方によっては非常に便利て、ある。 出力画面ウインドウ出力画面を表示す る。画面全体を切り換えずに出力画面を見 たいときなどに有効て、ある。 COM CHR8 COM 9600 [ 表 2 ] 田 OS 関数一覧 bi0S equiplist ルーチンは INT Ox 1 1 を使って , システムに接続してあるノ、一ドウェアや周辺装置 などを調べる。この関数で調べることができる周辺装置は以下のとおり。 ソースプログラムを コンパイル・リンク このウインドウに表示 ・ディスクドライプ ・数値演算コプロセッサ ・システム RAM のサイズ ・ピテオモードの初期値 ・インストールされているドライプ数 ・ DAM チップ ・ RS232 シリアスポードの数 ・ゲームアダブタ ・シリアルプリンタ ・インストールされているプリンタの数 unsigned _bios keybrd(unsigned service): bios_keybrd ルーチンは INT Ox 1 6 を使って , キーボードを制御する。 service 引数には , すれかの記号定数を指定する。 KEYBRD READ KEYBRD READY, KEYBRD SHIFTSTATUS NKEYBRD READ NKEYBRD READY NKEYBRD SHIFTSTATUS . り , ソーズウインドウにそのエラー該当場 所が表示されるタグジャンプ機能もある。 このうち , デノヾッグーヘルプ , ローカル 変数ーレジスタ , ノートパッドー出力画面 は同じウインドウを使い , タイトルバーの ◆をクリックすることにより切り換えて表示 される。 また , タイトルバーの * をクリックする ことによりそのウインドウを閉じたり , ↑ をクリックすることによりそのウインドウ をフルスクリーンサイズにて、きる。このあ たりのウインドウ操作は非常にわかりやす く , Ver. 2.0 の大きな魅力のひとっといえる だろう。 ◇トレース / ステップ プログラムを 1 行ずっ実行していく機能 て、ある。違いは , 呼び出した関数内もトレ ースするのがトレース , しないのがステッ プて、ある。 Ver. 1.1 て、トレースと呼ばれていた機能は Execute と呼ばれている機能て、ある。 る。 Ver. 1.1 て、はトレース , CodeView て、は ◇アニメート Ver. 2.0 て、はアニメートと呼ばれる。 プログラムをゆっくり実行する機能て、あ ー一面 e く 08i0. h ) include く 53i0. h ) ! link ⅵ物学引 i 「 . 面 J り な 第 / / ま : : 0 S:m S い田 : SP:(M) BP : Ⅳ : 歌 . CX:m DX : ドし : ・ W UP 田儿羅・ *H ・トー・一豊 -- ! イ空空 - ・豊 1 ー -- - デバ , 多行 D / 修正 / 補助 0 / 環境 H / フ・ Fig. 1 テノヾッグのウインドウ画面 次のい これによりシフトキーなどのそれ自体は文字コードを出さないキーのスキャンや , テンキーの押されて いる状態などを調べることができる。 unsigned biOS memsize(void); bion memsize ルーチンは INT 0X12 を使って , 使用可能なメモリの総量を調べる。 ー K バイト単位で使用可能なメモリの総量を調べることができる。 数には使用する通信ボートをたとえば 0 は COMI , 1 は COM2 というように指定する。 bios serialcom ルーチンは , INT 0X14 を使って , シリアルボート上の通信を制御する。 po 引 unsigned biOS serialcom(unsigned service, unsigned po 代 , unsigned databyte); ・ PRINTER STATUS P R ー NTE 日一 N げ PRINTER WRITE printe 「引数には出力先のプリンタを , e Ⅳ ice 引数には以下の記号定数をいずれかを指定する。 bios printer ルーチンは INT 0X17 を使って , プリンタへの出力を制御する。 unsigned biOS printer(unsigned service unsigned printe 「 . unsigned databyte); 引数 databyte では以下の指定が可能である。 COM STATUS COM RECEIVE COM SEND CO M ー N げ service 引数には , 次の記号定数のいすれかを指定する。 ・データのビット長 COM CHR7 ・ストップピット COM STOPI ・バリティー COM NOPARITY ・通信速度 COM 1 1 0 COM 600 COM 4800 COM STOP2 EVENPARITY 1 50 1200 COM COM COM COM ODDPARITY COM 300 COM 2400 unsigned biOS timeofday(int service, long * timeval); bios timeofday ルーチンは , INT Ox1A を使って , システムクロックの値を取得した り , 設定したりする。 service 引数には , 次の記号定数のいずれかを指定する。 CIS MAP 75 89- -8 23:01 CIS EXE 一 93 89-10-01 け 8 89-03- 0 : EXE ー IO-OI 3 6 聞 89- IO-OI 3 靆 6 く f トフ・〉 ( ニュ - 》く間インドく駅一 + ー再実行 ) 80 CMAGAZINE 1989 12 网 : 7 TIME GETCLOCK TIME SETCLOCK. Ver. 2.0 て、は実行速度を 3 段階に調節て、き るように機能拡張されており , 自分のハー ドウェアのスヒ。ードに合わせたりて、きるの て、非常に便利な機能て、ある。 ◇プレークポイント プログラムの実行を停止する行を設定す る。ただし , CodeView にあるような一時無 効化 , 回数指定といった機能はない 0 ◇ウォッチボイント / トレースポイント ウォッチボイントは指定した式が満たさ れたときにプログラムの実行を停止する。 Ver. 1.1 にはこの機能がなかったが , 今回 追加された。デバッグ時にはよく使う機能 なのて、 , 嬉しい追加て、ある。 トレースポイントは指定した変数の値が 変化した場合にプログラムの実行を停止す

5. 月刊 C MAGAZINE 1989年12月号

2.0 ていることが確認された。 イルスイッチ /0t これは , コン / ノヾ Quick List 2 void main() void *p; / * (a) ではなく , (b) のように展開される * / (void * ) f00 : (a) C の引数渡し を用いて最適化すると , BX に代入されたポ インタの値の生存範囲の判定を誤る場合が あったというものだが , 2.0 て、は解消されて いる (ListI)0Ver.1.1 ては初期化文字列の長 さに最大 512 バイトの制限があったが , これ も解消されている。ただし , 今回のバージ ョンになってから , データのポインタを関 数のポインタにキャストして呼び出す場合 に , 引数渡しが Pascal 形式になってしまう ことが発見された (List2) 。 コンパイルスピードの比較については , 表 1 に示したようになる。ただし , インクリ メンタルコンパイル & リンク機能により , 未変更の部分についての作業を省略するこ とがて、きるのて、 , コンノぐイルとリンクの時 間がかなり短縮される。このインクリメン タルコンパイル & リンク機能が , 今回のバ ージョンアップの大きな特長となっている。 最適化 ストアする。この点は MS-C に似ている。 は使用がすんだら値をローカル変数領域に ローカル変数領域を使わないが , QuickC て 変数にしてしまい , スタックフレーム上の と似ているが , TurboC ては完全にレジスタ タを用いるようにしたようだ。これは TurboC 関してはメモリて、はなく動作の速いレジス かもしれない。③についてだが , ループに ①②ともそれほど本質的なことてはない ③ループ変数のレジスタ割りつけ の省略 ②不必要な S 工 , D エレジスタの PUSh,POP ①スタックチェックの省略 ような最適化が行われていた。 このプログラムによる比較の結果 , 次の べるものて、ある。 っかのテーマのもとに最適化のようすを調 た。このプログラムは後述のとおり , いく が変わるかを List3 のプログラムて調べてみ デフォルトの場合とて , どのようにコード 最大最適化スイッチ / Ox を用いたときと MOV MOV MOV PUSH MOV PUSH CAL し ADD Word Ptr [BP-02] Word Ptr [BP AX, 0002 AX AX, 0001 AX FAR [BP-04] SP, + 04 (b) Pasc の引数渡し ー 04 ] , Word Ptr [BP-04], offset f00 MOV MOV MOV PUSH MOV PUSH CA しし Word Ptr [BP-02] AX, 0001 AX AX, 0002 FAR [BP-04] , seg f00 offset f00 : 引数ブッシュ : 引数ブッシュ 関数呼び出し : スタック調整 , seg f00 引数ブッシュ : 引数ブッシュ 関数呼び出し ほカコンノヾイラとの比較 ほかのコンパイラと最適化の比較をして みる。使用したコンパイラは次のとおり。 QuickC Ver. 2.0 十 MSLINKVer. 4.06 MS-C Ver. 5.1 十 MSLINKVer. 3.65 TurboC Ver. 2.0 十 TLINKVer. 2.0 LSIC Ver. 3.10 十 MSLINKVer. 3.65 ZortecC Ver. 1 . 06 十 BLINKVer. 2.15 List3 をそれぞれ最大最適化状態て、コンパ イルし , 生成コードを調べてみた。 for ループの基本形を Fig. 1 に示したが , for ループに関しては , 次のような最適化が 考えられるだろう。 ①ループが単純な繰り返して , その内容と 独立しているとき , つまり , ループ変数が D の部分て参照されていない場合には , 速 いループ構造を適用することがて、きる。た とえば , 10 回ループならば , 「 0 が 10 になる まて、」よりも「 10 が 0 になるまて、」のほうが簡 単にすむ。 ②初期値 A が明らかに条件 B を満足してい れば , 2 行目の JMP @ 1 が省略てきる。 れにより , 条件判別とジャンプが 1 回省け ③不変式をループの外に追い出す。 List3 の 関数 15 ( ) て、 , b=a * 2 ; の値は , ループ中て、不変て、あり , ループに 入る前に計算しておくことがてきる。 ④ループ変数に比例して値が変わる変数に ついての最適化。関数 14 ( ) て、 , 変数 i と a はそれぞれ , i ー 01254 5 6 7 8 9 a ー 1 5 5 7 9 11 15 15 17 19 と変化する。変数 a をいちいち i から計算 するのてはなく , 2 ずっ増加するものだと みなす。 次に , 定数の扱いについての最適化をみ a) C のソースコード b) 生成コード JMP D ] [ C ] Jcond @ 1 : @2 : @2 @ 1 第 2 特集 QuickC ver. 2.0 徹底チェック 87

6. 月刊 C MAGAZINE 1989年12月号

五ロ はじめて学ぶプログラー ニンク 匚ー = コ メントする ( 1 増やす ) ということてした。 て、すから , 変数 i が 0 のときは , まず printf 関数て、 ' 工 = O ' と出力された後に i がインクリ メントされて 1 になります。 こうして 10 回ループした後て、 w ⅲ le 文か ら抜け出し , 11 行目て、ループの外に出た とを出力しています。 Fig. 4 wh ⅱ e 文の制御構造 (a) 1 文制御 while ( ① ) ② : Fig. 5 do - wh ⅱ e 文の制御構造 (a) 1 文制御 ( b ) 複文制御 do do ー ① while ( ② ) ・ ( b ) 複文制御 while ( ① ) ① while ( ② ) ・ NO ①か真 ? YES. ②の実行 ①の実行 0 が真 ? NO YES do-while 文の書式と制御構造 do-while 文は , while 文と同様に繰り返 しを制御します。 while 文て、はまず繰り返し の判断をしてから次の処理を行いましたが , 式を判断します。そして①式が真の間は② do ー while 文は , 文を実行してから繰り返し の判断がされます。 が繰り返し実行され , 偽になると while 文 から抜け出します。 while 文て、は , ①式が最 書式 初から偽だと②がまったく実行されない dO ともあります。 なっています。 C 言語の d0 ー w れ ile 文はその 逆て、 , 真のとき繰り返し , 偽のときループ を抜け出るのて注意してください do-while 文の例 while 文の例 List5 は List4 の while 文を d0 ー while Fig. 5 が do-while 文の制御構造て、す。ま 文に書き換えたものて、す。 List4 と同じよう ず①が実行され , その後て、②式が判断され に処理したあと , 9 行目から 11 行目にかけて List4 は 10 回ループを繰り返し , while 文 ることがわかるかと思います。②式が真だ の制御変数の値を出力するものて、す。ます , do-while 文がきています。変数 i の初期値 と①が繰り返し実行され , 偽になるとルー は 0 て、あるため , まず関数 printf て、 ' 工 = 0 ' 3 行目て繰り返しの回数をマクロ定義して プから抜け出ます。 while 文と異なる点は , と出力された後 , i がインクリメントされ 1 います ( コラム 2 参照 ) 。 7 行目て、 int 型の制 ①が必ず一度は実行されることて、す 0Pascal となり , MAX( = 10 ) と比較されます。この 御変数 i を宣言すると同時に O て、初期化し , などを知っている人への注意て、すが , PascaI 場合 , 値が真となるためループを繰り返し 9 行目て、変数 i と MAX ( = 10 ) とを比較し の repeat-until 文て、は until の式が偽のと ます。そして変数 i が 10 になるまて、繰り返 て真ならば printf 関数て、変数 i を出力して き繰り返し , 真のときループを抜け出ます。 し ,i が 10 になるとループから抜け出ます。 います。 こて、復習て、すが , こて、注意してほしいのは , while 文と do そのほかの手続型言語のほとんどは Pascal -while 文て、条件式がまったく同じ点て、す。 のように真のときループを抜け出ることに は , 変数 i を評価した後て、変数 i をインクリ 文 : while ( 式 ) : i 十十 List 4 Li st 5 1 : #include く stdio. h> 2 : 3 : #define MÅX 4 : 5 : void main() 7 : int i 8 : 9 : whi le ( i く MAX ) printf()l = %dYn" printf("0ut of the while 100P. yn") : 1 : #include く stdio. h> 2 : MAX 3 : #define 4 : 5 : vo i d ma i n ( ) 7 : 9 : do printf("l = %dYn ” while ( i く MAX ) : printf("0ut 0f the do-whi le OP. Yn") : はじめて学ぶ C プログラミング 117

7. 月刊 C MAGAZINE 1989年12月号

Fig. 3 exec 系関数の流れ図 execl( ) execle( ) execlp( ) execl pe ( ) execv ( ) execvpe ( ) execvpe ( ) execve( ) -doexec ( ) 関数はアセンプラで作成されているが、そのほかはすべて C で作成されている。 Fig. 4 spawn 系関数の流れ図 spawnl() spawnle( ) spawnlp( ) spawnlpe( ) spawnv( ) spawnvp( ) spawnvpe( ) spawnve( ) -d oexec ( ) -dospawn( ) -dospawn ( ) 関数はアセンプラで作成されているが、そのほかはすべて C で作成されている。 [ 表 3 ] そのほかの関数のプロトタイプ a. system( ) 関数のプロトタイプ く process. h 〉 く stdlib. h 〉 int system (const char *command); b. exit() 関数 , -exit( ) 関数のプロトタイプ く process. h 〉 く stdlib. h 〉 void exit (int status); VOid exit (int status); c. abo ( ) 関数のプロトタイプ く stdlib. h 〉 く process. h 〉 void abort (void); MS ーロ OS プログラミンク、入門 ラムを見ていただきたい ・関数同士の関係 る。 system ( ) 関数の実行について成功した ァイル以外は親の条件とほとんど同じて、あ ければならない。つまり , オープンしたフ トされているディレクトリに位置していな レクトリか , 環境変数て、ある PATH にセッ る。実行するプログラムは , カレントディ イルあるいはほかのプログラムを実行させ て、与えた MS ー DOS コマンドや , バッチファ command / c 文字列 出し , ら , MS-DOS の COMMAND.COM を呼び system( ) 関数は , C プログラムの中か 表 3 ・ a にプロトタイプを示す。 立てて文字列ポインタとして引き渡す。 COM の引数として指定された文字を組み tem() 関数に与えた引数を COMMAND. COMMAND. COM を呼び出し , sys system( ) 関数 ・そのほかの関数 関数と同じて、あろう。 awn( ) 関数は , オーバレイを除いて doexec( ) ムの消去とメモリの再配置を行う。 dosp メモリの空きを見つけ , そして親プログラ 内容としては , MCB を調べることによって は , これらの関数が最終的に実行される。 exec 系 , spawn 系関数によるプロセスて、 は , アセンプラによって記述されている。 doexec( ) 関数および dospawn( ) 関数 に示すことにする。 れている。 Fig. 3, Fig. 4 にその関係を具体的 て , ランタイムライプラリとして C て、記述さ exec 系と spawn 系の各 8 つの関数はすべ C プログラマのための MS ー DOS プログラミング入門 67 場合は 0 を , 失敗した場合には一 1 を返す。

8. 月刊 C MAGAZINE 1989年12月号

2 ⅲんは MS ー C5.1 と互換性のある手ごろな C コン、イラかないとご不満の皆さん ウインドウ、関数内で定義されたローカル変 スウインドウにコヒーすることも可能ですまた、 QuickC2.0 は世界標準の C コンパイラ、、 MS ー 数を自動表示するローカルウインドウか追加 コンヾイルエラーの説明もすぐに参照できます C5.1 ′′と完全な互換性をもち、快適なプロク され、 CodeView デバッガに優るとも劣らな ラミンク環境と MS ー DOS 上最強の機能を いデバッグ機能をも実現しました。さらに、イ 提供する C コンパイラです他のコンパイラ ンラインアセンプリコード部分もそのまま行ト にありがちな「 MS ー C5.1 との互換性がない」 レースできます 「アセンプラで関数を書くと、リンクか面倒」 「分厚いマニュアルをいちいち読みたくない」 「プロクラムメンテナンス機能か貧弱だ」「使 いなれているエテイタで書きたい」「アセンプ ラやテパッカを買い足さなければ使えない」 ・ QC アドバイサ ( 関数の説明 ) などといった問題点を解決。統合環境での 制約事項も大幅に取り除きました。また、 MS- さらに付属の HELPMAKE ユーティリティを C5.1 の MS ー DOS 上の機能をほほ・実現する 利用すれば、標準のヘルプファイルを作り とともに、 MS ー C5.1 にはないさまざまな機能 直したり、オリジカレのヘルプファイルを作成 をも備えています。さらに、初めて C 言語を学 することもできます ぶ方のための機能も豊富に追加され、プロ ユースから C 言語の学習まて最良の C コン パイラとしてご活用いただけます 変更は 上当て ノンパ・一ドファイノレ ! : 第 黶プを己佇 - - ・の朝三 . 環まの当定によらて度をざれます。 ーて官されていま ! 第 ! が呼びヒされると . 変第ンⅱ・い“ : 「・・をび - に次の価が されます . : i 化 ! : E ヨ石 三 0 匚 ! : れ ( 0 」な・ : h. を i 、物 . 4 を . 作ー . を′を ) : ′・ファイルが有在しない場合をそれをオープンする . ・ QCCONFIG メニューには MS ー DOS コマンドを追加可能。 つまり、普段使いなれているエデイタや、 MS- C5.1 に付属している Microsoft Editor や C0deView を登録し、ショートカットキーで簡 単に実行することができます 登録の際には、コマンドだけではなくコマンド 引数 ( ファイル名やプログラム名 ) も合わせ て登録することができます こ刀 - 価 0 ) 0 れ・を : 、 0 : 0 8 ・一一を : ッお・ 4 tC•・ン ・テノヾッグ画面 豊富なユーサーカスタマイス機能 インラインアセンプリ機能の追加 編集キーの割当てを変更する MKKEY ユー インラインアセンフラの内蔵により、アセンフ リコードを C プロクラム内に記述することか ティリティ、画面の表示色を自由に選べる できるようになりました。この機能は、インテル QCCON 曰 G ユーティリティが装備されています PC ー 9800 シリーズの OS コールを直接サ 8086 / 8087 / 80286 / 80287 の命令セットをサ ポートします * 統合環境上での制限事項を大幅に取り払 アセンフルを行う際に、 Microsoft Macro いましたスモール、ミディアム、コンヾクト、ラー Assemb は必要ありません ジ、ヒュージのすべてのメモリモデ丿レを統ロ * ただし 80286 / 80287 命令セットは統合環境上では 環境上でサホート。使用する関数も統合環 利用できません 境上ですべて利用可能です さらにメモリモデルやテンヾックオプションの指 定も、統合環境上で行えますテパッグオプ ションを付けてコンヾイル & リンクした実行フ ロクラムをそのまま CodeView テンヾッガでデ バッグできます B ℃ S ライプラリの追加 MS ー C5.1 との互換性強化 ー秘′ ( ・ 0 ) 平方根はです . ・ . ルト石 0 / 9 「第一 ~ 等 0-0 ト 雑定望、める ・面取 . 2 舅袴叟トから 進化したオンラインヘルプ = QC アトパイサ オンラインヘルフ機能をさらに強化した QC アドバイザにより、いちいちマニュアルを読まな くても、 Ou ℃ kC2 ℃のメニューの使い方、タイ アログボックスのオプション設定、編集機能 Ou ℃ kC2.0 は非常に強力なテパッグ機能を の操作方法、 C の文法、関数の説明、構造 備えていますトレース、ステップカーソル位 体や定数の説明などがコンヒュータ上で学 置までの実行に加え、フレークポイント、ウォ べますハイバーリンク形式なので関連する ッチボイントの定義、ウォッチ変数の値の変 関数や説明などの呼び出しも簡単です 更、テパックまでの操作を記憶するヒストリ この QC アドバイザのヘルプウインドウは独 機能などがありますヒストリ機能では、現在 立しているため、 C の文法や関数の説明を までのテパッグ操作を簡単に再現すること 参照しながら編集作業を続けられます全ラ ができます ンタイムライフラリ関数の説明には、サンプレ また、ウォッチ変数を表示するテパッグウイン プログラムが付属していますヘルフウインド ドウ以外に CPU レジスタを表示するレジスタ ウにカーソルを移動させて、その内容をソー ・インラインアセンプリ機能 豊富で強力なテパッグ機能 YAMAHA ID>< フ 飆 lllllllj 、 0 0 0

9. 月刊 C MAGAZINE 1989年12月号

Quick 2.0 List 4 word ptrCBP-2] , AX AX, word ptr[BP + 6] AX AX, 引 AX, 3 word ptr[BP-4] , AX word ptr[BP-2] CS near ptr ー f00 SP, 2 word ptr[BP-4] CS near ptr ー f00 SP, BP る て ーし 用 使 で 行 第 お て 保 に タ ス ジ レ ーレ 算 計 を で ) 行 0 1 ーっ 0 C•-) -4 ・ - -0 ^ 0 々ー 8 0 1 よワ 0 っ 4- - -0 ′ー、 第 1 よ 1 よ 11 1 よ 11 1 よ 1 よ -14 1 よ、 1 ワ 0 っ 0 っ 0 ワ朝ワレワ〕っ 0 far ptr ー f00 word ptrCBP-4] far ptr ー f00 SP, 2 SP, BP call add push call add mov POP retf 17 : 20 : 22 : 23 : 24 : ( 解説 ) i * 2 の計算を 2 度行っている ( 第 5 , 6 行と第 11, 12 行 ) 。 MS-C 1 : c2 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : mov mov i mu I add add mov push push call add push push ca Ⅱ add PO P mov POP retf BP BP, SP SI, word ptr[BP + 6] S I , 1 ÅX, word ptr[SI+1] push mov sub push mov shl lea [ 表 2 ] 最適化度 ①高速ループ ②判別省路 ③不変式追出 ④誘導変数 ⑤定数 1 ⑥定数 2 ⑦共通部分式 注 ) コンバイルスイッチ ( 表 2 表 4 まで ) QuickC. MS-C : /Ox Tu rboC —O —Z —G [ 表 3 ] コンバイル時間 ( sec ) QuickC Lista DHRYSTONE WHETSTONE 28 凵 SP 1 40 29 g 「 ( * ) IO 分を超えた。 [ 表 4 ] EXE のサイズ (bytes) QuickC MS-C Tu rboC LS ℃ ZortechC 凵 sta 2761 2729 2766 4252 41 56 DHRYSTONE 1 0 日 63 1 0571 951 6 1 2025 1 1 246 WHETSTONE 28850 291 60 28924 24468 29047 日 4789 * 凵 SP 90043 * 40902 391 56 431 92 1 461 5 1 3521 1 379 日 1 4766 9 日 38 g 「 eD * EXEPACK 後は QuickC も MS-C も 40K バイトほどになる。 [ 表 5 ] EXE の送行時間 (sec) QuickC Lista 2.3 DHRYSTONE 46 WHETSTONE 95 凵 SP 5.5 2.0 g 「 eD * ( ) 内はダミー関数 f00 ( ) を日 EP のみにした場合 注 ) PC-9801VM 10MHz 8087 なし十 HDD(seek time 20ms) てみよう。 ⑤関数 cO ( ) の中の 4 十 5 * ( 2 十 i 十 1 ) は , Quic kC TurboC ▽ ▽ ▽ ▽ △ ▽ △ ZortechC ▽ 0 0 ▽▽▽▽▽▽▽ 〇〇〇 0 0 △ 0 ▽▽▽▽△▽▽ ~ i * 5 十 15 と書きくだすことがて、きる。 ⑥関数 cl ( ) の変数 a , b , c は , コンパイル 時にそれぞれ 5 , 2 , 5 と明らかになる。 ⑦共通部分式の省略。関数 c2 ( ) の , の部分は x と y とて、共通だから , 適当な場 所に退避しておけば 1 回の計算て、すむ。 さて , 以上のテーマの各コンパイラて、の 結果を表 2 に示す。表て、〇は期待どおりの最 適化が行われている , △は不十分て、はある が何らかの最適化が行われている , ▽は期 待した最適化はあまり行われていない , と いうことを示している。 List4 に QuickC が生成したコードと , き ちんと最適化したコンパイラのコードを示 したのて、参考にしていただきたい List3 のほかに , DHRYSTONE, WHET STONE, LISP インタブリタ , LSIC に付 属の grep をそれぞれコンパイルし , コンパ イル時間と EXE のサイズと EXE の実行時 間を表 3 ~ 5 に示す。 LISP はハノイの塔 (LEVEL8) の実行時間 , grep は f. * p. * 第 2 特集 QuickC Ve 「 .2.0 徹底チェック 91 ZortechC LS ℃ . none i * 2 Zortec h C 29 46 260 77 LS ℃ 1 22 1 94 Tu rboC 5 9 1 3 60 MS-C 39 49 31 0 LS ℃ ZortechC 1 . 日 * 2.3 ( 1 .9 ) 36 36 1 05 66 5.6 2.0 MS-C Tu 「 bo C 2.2 2.5 ( 2.2 ) * 37 44 75 59 4.4 5. O

10. 月刊 C MAGAZINE 1989年12月号

ーコンヾイラ の ( 173 行 ) の 2 とおりのものがあります。ま たエラーリカバリの都合から , if 文の「 if ( 式 ) 」という部分をノンターミナル if head として独立して定義しています。 while 文 , for 文 , switch 文についても , 同様に頭部 を表す XXX head というノンターミナルを 設けています。 177 行目は while 文 , 178 ~ 180 行は dO ~ w れ ile 文て、す。 181 行目は for 文て、す。 for 文のカッコ内には 3 つの式が書けます が , いずれも省略て、きます。式を省略可能 にするために , for head の定義て、 expr 0Pt というノンターミナルを参照しています ( 208 行 ) 。 expr 0Pt は , 何もない ( 212 行 ) か , 式がある ( 213 行 ) か , というふたつの規 則をもっています。 182 行目は , switch 文て、す ocase 文は 183 行目 , default 文は 186 行目て、定義していま す。以下 , 189 行目から 198 行目にわたって , break 文 , continue 文 , return 文 , goto 文 , ラベル付文 , 空文と続きますが , いず れも説明の必要はないて、しよう。 104 行目から 160 行目まて、が宣言の定義て、 言の定義 す。 て、は , declaration, declar ator, type name の 3 つが「外部シンボ、ル」 て、 , このほかは補助的なノンターミナルて、 す。 declaration は , いわゆる宣言のこと て、 , 型指定子 (type specifier) の後に宣言 子 (declarator) を 0 個以上 , コンマて、区切っ て並べ , 最後にセミコロンをおいたものて、 す ( 104 ~ 106 行 ) 。たとえば , 次の 3 行 int a, b, c [10] C20] ・ int は 1 行 1 行が ( それぞれ完結した ) 宣言て、す。 こて、 , int と char が type specifier て、 す ( 108 ~ 110 行 ) 。また , *p や (*fp)() や c [ 10 ] [ 20 ] が declarator て、す。宣言子 は , declarator と decIarator2 のふたっ のノンターミナルを使って定義されていま 78 CMAGAZINE 1989 12 す。これは , 宣言に優先順位 ( ポインタ ' * よりも , 関数呼び出し℃ ' や配列 ' ロ ' を優 先する ) をつけるためて、す。 122 行目はカッコを使ってのくくりだして、 す。それに対して , 124 ~ 125 行は関数呼び 出しの宣言て、す。このうち , 125 行目はパラ メータ付 2 の関数宣言て , パラメータ自体は param list ( 131 ~ 138 行 ) を使って定義さ れています oparam list は , param decl を ひとつ以上コンマをはさんて、並べたものて、 す。 param decl は , 型指定子 (type specifier) と宣言子 (declarator) を並べ たものて、す ( 140 ~ 141 行 ) 。 144 行目から 160 行目まて、が , 型名 (type name) の定義て、す otype name は , キャス トや sizeof を定義するのに使います ( 251 , 252 行目 ) 。 type name の定義には , 抽象宣 言子 (abstract declarator) を使います。 抽象宣言子は , 宣言子 (declarator) から識 別子を取り除いたものて、 , abst declarator として 148 ~ 160 行て定義されています。抽 象宣言子は宣言子から識別子をなくしたも のなのて、すが , たんに declarator/declar ator2 の文法規則の工 DENT 工 FIER をな くして空の規則にするだけて、は , conflict が 起こり , うまく処理されません。そこて、 , 型指定子宣言子関数本体 関数の定義 ( func def) は , をおくことがて、きます。 78 行 ) て、す。いずれの場合て、も前に EXTERN の定義 ( 75 , 76 行 ) , または変数の定義 ( 77 , ものて、す ( 65 , 66 行 ) 。 extern def は , 関数 が ) 。 file は , extern def を 1 個以上並べた す (program という名前のほうが適切て、す Cm コンパイラのメインエントリは , file て、 のトップレベルのプログラムの定義て、す。 65 行目から 99 行目まて、が , Cm コンパイラ プログラムの定義 してあります。 は , conflict が起きないように文法を変形 abst declarator/abst declarator2 て、 の内部を詳解 か 宣言子関数本体 のいずれかが許されます ( 82 ~ 88 行 ) 。 たとえば , int foo(char * p) 博道・田中啓介訳 , 啓学出版 , 1987 『コンパイラ設計』矢吹道郎・小暮 Hall, 1985 H. Gerorge Friedman Jr. 著 Prentice tion with UNIX, Axel T. Schreiner, [ 1 ] lntrouction tO compiler construc 参考文献 を説明する予定て、す。 ルアナライザから宣言の処理ルーチンまて、 していくことにします。次回は , レキシカ 降 , 関連するトピックのところて、適宜追加 ーサて、す。 cm. y のアクションは , 次回以 まったくアクションをつけていない裸のパ することがて、きました。 List2 の状態て、は , これて、 , ようやく Cm 言語の文法を定義 カル変数を定義て、きるようにしてあります。 化するために , 関数本体の先頭て、のみロー Cm て、はシンポルテーカレの取り扱いを簡略 ーカル変数を宣言することがて、きますが , す。本来の C 言語て、は , 複合文の先頭て、ロ ーカル変数を定義て、きる点が異なっていま ( 220 ~ 224 行目 ) と似ていますが , 先頭て、ロ 関数本体 ( func body) は複合文 ることにします。 階て、 , 言子が関数て、あるかをチェックす されてしまいます。そこて、 , 意味解析の段 この定義て、は文法的には正しいものと認識 などは , 本来ならエラーにするべきて、すが , int a[10] ん。てすから , 言子は関数を表すものて、なければなりませ 言子 , { } が関数本体になります。当然 , 宣 て、は , int が型指定子 , foo(char * p ) が宣