Li st 8 トなプログラムを作成するための機能を備 えています。プロトバージョンはすて、にパ move. 1 8 ( a の , a0 116 : c 叩 . 響 # 30 , (a の 117 : ソコン通信て、入手可能になっていますのて、 , 118 : bne ? 63 119 : ?PB21: 興味のある方は参加されるのもいいと思い addq. 1 # 1 , ? PBX2 + 84 120 : c 叩 . 1 4 ( a の , d4 121 : ます。 122 : bne ? 63 123 : QPB22: 某ゲーム雑誌にて某 X68k 有名ソフトハウ addq. 1 # 1 , ? PBX2 + 88 124 : move. b 3 ( al ) , d0 125 : ス [ 注 4 ] の方が「 C て、は遅くて・・・・・・」とおっし lsr. b # 4 , d0 126 : 田 ove. b d0, d3 127 : やっておられますが , GCC て、は「下手なアセ btst # 0 , d3 128 : bne ? 63 129 : ンプラ」より速いことが多々あります [ 注 5 ] 130 : ?PB23: addq. 1 # 1 , ? PBX2 + 92 131 : move. 1 a3, -(sp) 大規模なソフトをアセンプラて、記述するの 132 : jsr —delete—insn 133 : addq. w # 4 , sp はアマチュアには手が出ないものて、す。複 134 : 135 : ? 72 : 136 : ?PB24: 雑なアルゴリズムもメンテを考えるとアセ addq. 1 # 1 , ? PBX2 + 96 137 : c 叩 . w # 13 , (a3) 138 : ンプラは躊躇します。一見アセンプラガリ 139 : bne ? 67 140 : ?PB25: ガリのようなゲームて、も大半は C だったりし addq. 1 # 1 , ? PBX2 + 100 141 : move. 1 16 ( a3 ) , al 142 : ます。要は「バカとハサミは使いよう」だと c 叩 . w # 25 , (al) 143 : 144 : bne ? 67 思います。 145 : ?PB26: addq. 1 # 1 , ? PBX2 + 104 146 : move. 1 8 ( al ) , a0 147 : c 叩調 # 30 , (a の 148 : [ 注 1 ] bne ? 67 149 : 150 : ?PB27: NIFTY-Surve FSHARP にアップロードさ addq. 1 # 1 , ? PBX2 + 108 151 : c 叩 . 1 4 ( a の , d4 152 : bne ? 67 れています。 153 : 154 : ?PB28: addq. 1 # 1 , ? PBX2 + 112 155 : [ 注 2 ] move. 1 4 ( al ) , a0 156 : c 叩 . # 37 , (a の 157 : 環境変数の、、まりこ〃は漢字の場合は「真里 bne ? 67 158 : 159 : ?PB29: 子」て、す。 10 月号 P172 の補足説明は間違っ addq. 1 # 1 , ? PBX2 + 116 160 : move. b 2 ( a0 ) , dl 161 : ています ( これは FEP が悪い。「まりこ」て、変 c 叩 . b # 3 , dl 162 bhi ? 67 163 換するとたいていは「真理子」になるからね addq. 1 # 1 , ? PBX2 + 120 165 え。ちなみにこの「真里子」は『少年サンデ 田 ove. 1 4 ( a4 ) , d0 166 moveq. 1 # 7 , d2 167 ー』のマンガにて、てくる女の子の「真里子」 c 叩 . 1 d0,d2 168 169 blt ? 67 て、はありません ( 誉 ; ) ) 。 addq. 1 # 1 , ? PBX2 + 124 171 [ 注 3 ] move. 1 d0, -(sp) 172 move. b dl, d3 173 GCC の作者 R. M. Stallman 氏は #pragma に move. 1 d3, -(sp) 174 peaW 34 175 関しては批判的て、す。が , この場合はよい 176 Jsr —gen—rtx move. 1 16 ( a3 ) , a0 177 方法がほかになさそうなのて、・・・ move. 1 d0, 8 ( a の 178 lea 12(sp), 179 [ 注 4 ] 蛇足て、すが , このメーカーさんの第 1 作には addq. 1 # 1 , ? PBX2 + 128 182 move. 1 12 ( a3 ) , a3 183 偶然動いていたという類のバグがあります。 c 叩 . 響 # 0 , a3 184 185 bne ? 78 [ 注 5 ] 187. ?PB33: addq. 1 # 1 , ? PBX2 + 132 188 : プログラム全体としてみれば , GCC も人間 move. 1 12 ( a5 ) , a5 189 : 190 : c 叩 . 響 # 0 , a5 には決して勝てないて、すが , 短いプロック 191 : bne ? 79 192 : ? 81 : て、の命令のクロック数て、はたいてい GCC が movem. 1 ( s の + , d3/d4/a3/a4/a5 193 : 194 : rtS 最小て、す。 meve. 1 # 2 , .. をいつばい並べた よりは・・・ 144 C MAGAZINE 1992 1
List 7 詳細プロファイラ機能としてプロック単 位て、の実行回数を計測て、きます。コンパイ 22 : ル単位全体をプロック単位計測する場合は 23 : 24 : -a オプションを指定してコンパイルしてく 25 : 26 : ださい。プロック単位プロファイラてはラ 28 : イプラリは自動リンクしないのて、 , 明示し 30 : て proflib. a(. l) をリンクしてください 32 : TabIe 2 カⅨ 68000 版 GCC の独自最適化ル 33 : 34 : ーチンソースて、のプロックプロファイル結 35 : 36 : 果て、す。 List 7 がそのソース , List 8 が Lis 38 : t 7 をコンパイルしたアセンプラソースて、 39 : 40 : す。 if 文は条件ごとにプロック分割されてい 41 : 42 : 43 : これらの結果のように , 非常に細かな実 44 : 45 : 行単位て、実行回数を計測て、きますが , 大き 46 : なファイルて、これを行うのはかえって不便 48 : なだけなのて、 , # pragma て、プロック単位てプ 50 : ロファイルをする部分を指定て、きます [ 注 3 ] 。 52 : 53 : #pragma bl 。 ck て、「行う」「行わない」の条 54 : 55 : 件が反転します。たとえばヾー a 〃て、全体を 56 : プロファイル指定してあったら , 58 : #pragma block に出会った時点からプロ 59 : 60 : ファイルを行わなくなります。再度 #pragm a block に出会うとその時点から , プロファ イルを行います。、、一 a 〃が指定されていない と #pragma block に出会うとその時点から 1 . even ・・となるわけて、 プロファイルコンノヾイル・・ ”田 . 1 d3/d4/a3/a4/a5, ー (sp) 3 tst. 1 ?PBXO す。 #pragma block は必ず top level になけ 4 bne ?PI 2 5 6 pea ?PBXO ればなりません。関数内部を #pragma b10 bb_init_func 7 JSr addq. 響 # 4 , sp 8 ck て、分けることはて、きません。行った場合 はどんな動作をするかわかりません。 addq. 1 # 1 , ?PBX2 + 0 11 no 冊 . 1 24(sp),a5 12 プロファイル結果はソースのアセンプラ c 叩 . 響 # 0 , a5 13 レベルて、のコンノヾイルコードソースを作っ ておかないとほとんど意味がありませんし , addq. 1 # 1 , ?PBX2 + 4 0 叩 . 響 # 13 , (a5) 18 ソースとの対応などわからない人て、はまっ bne ? 63 19 たく無用の長物て、す。このプロファイラは addq. 1 # 1 , ? PBX2 + 8 move. 1 16 ( a5 ) , a0 22 少々知識が必要ということになります。 c 叩 . w # 25 , (a0) 23 24 bne ? 63 int prof size addq. 1 # 1 , ? PBX2 + 12 26 move. 1 8 ( a の , al 27 プロファイラを行うソース単位て、の最 c 叩 . 響 # 30 , (al) 28 29 bne ? 63 大数を指定します。プログラムて明示・ addq. 1 # 1 , ? PBX2 + 16 初期化すれば増やすことがてきますが , move. 1 4 ( a の , a0 32 c 叩 . 響 # 34 , (a0) 33 30 個確保しますのて , まず通常て、は問題 Ⅱ GET-CODE (st) = JUMP_INSN Ⅱ GET_CODE (st) = CODE_LABEL) break : if (GET_CODE (st) = INSN & & (GET_CODE (PATTERN (st)) = PARALLEL Ⅱ GET-CODE (PATTERN (st)) = = ASM-OPERANDS)) break ; if (GET_CODE (st) = INSN & & GET-CODE (PATTERN (st) ) = SET & & reg—mentioned—p (reg, SET—DEST (PATTERN (st)))) rtx dest = SET_DEST (PATTERN (st)) : if (GET_CODE (dest) = 三 REG & & REGNO (reg) = = REGNO (dest)) if (GET_CODE (SET_SRC (PATTERN (st))) = = CONST_INT & val ー = INTVAL (SET_SRC (PAffERN (st))) & & IREG_USERVAR_P (SET_DEST (PATTERN (st)))) delete—insn (st) : else break; else break; if (GET_CODE (st) = INSN & & GET_CODE (PATTERN (st)) = SET & & GET_CODE (SET_SRC (PATTERN (st))) = CONST_INT & & val INTVAL (SET_SRC (PATTERN (st))) & & GET_CODE (SET_DEST (PATTERN (st))) = MEM & & (int) GET—MODE (SET—DEST (PATTERN (st))) く (int) SImode & & REGNO (reg) く 8 ) SET_SRC (PATTERN (st)) = gen—rtx (REG, GET—MODE (SET—DEST (PATTERN (st))), REGNO (reg)) : LiSt 最適化ルーチンをコンパイルしたアセンプラソース 142 C M AGAZIN E 1992 1
List 8 ないて、しよう。 int block prof exit ( ) を呼び出す前か , main() を終 わる直前に 0 にすればプロファイラ情報を 出力しません。 FILE *_block prof file プロファイラ結果を書き出す FILE 構造 体へのポインタて、す。 NULL( 初期値 ) の 場合は stdout に出力します。 void display_profile (void) 明示的に呼び出せばその時点てのプロ ファイル情報を出力します。 終わりに 冒頭から「バグレポート」の羅列て、 , 「 X68 000 版 GCC ってバグがたくさんあるんだ・・・ と思われた方もいらっしやるて、しよう。て、 も , 68881 関係のバグ以外は私が移植改造し た GCC にかなり長い期間潜んて、いて発見さ れたバグなのて、す。バグフリーて、あるわけ はなくとくに私が移植した GCC は CPU パワ ーが低い 68000 て、 1 クロックて、も削るように また少して、も便利なようにオリジナル GCC から大幅に変更を加えてあります。 GCC が Ver. 1.40 になった時点からバージ ョン表示て X6 ? ? (Based on 1.40 ) と表示す るようになったのは , かなりオリジナル GC C から逸脱したコード生成をするようになっ たためて、す。 現在 , GCC はおもにパソコン通信て、サポ ートしていますがこの℃マガジン』て、だけ しかサポートを受けられない読者の方々も , 何かの不具合 , 疑問要望などがありました らご連絡ください。サポートを保証するわ けてはありませんが , この GCC は熱心な X6 8000 ューザからの多くバグ報告 , 要望て現 在の形になった亜流 GCC てす。また現在 , SX-Window 専用の GCC, assembler, link er が開発されつつあります。 これらは , SX ー Window の C アプリケーシ ョンを開発するためにとくにリエントラン bne ? 63 34 addq. 1 # 1 , ? PBX2 + 20 36 c 叩 . b # 4 , 2 ( a の bne ? 63 38 addq. 1 # 1 , ? PBX2 + 24 move. b 3 ( a の , dl 41 ls 「 . b # 4 , dl 42 moveq. 1 # 0 , d0 43 44 move. b d1,d0 btst # 0 , d0 bne ? 63 addq. 1 # 1 , ? PBX2 + 28 move. 1 12 ( a5 ) , a3 move. 1 a0, a4 50 mo 冊 . 1 4 ( al ) , d4 51 c 叩調 # 0 , a3 52 beq ? 63 53 addq. 1 # 1 , ? PBX2 + 32 55 moveq. 1 # 0 , d3 56 addq. 1 # 1 , ? PBX2 + 36 59 move. 響 (a3),d0 60 c 叩 . 響 # 15 , d0 ? 63 62 addq. 1 # 1 , ? PBX2 + 40 64 c 叩 . 響 # 14 , d0 65 addq. 1 # 1 , ? PBX2 + 44 68 c 叩 . 青 # 17 , dO 69 . b ? 63 addq. 1 # 1 , ?PBX2 + c 叩 . 響 # 13 , dO bne ? 70 addq. 1 # 1 , ? PBX2 + 52 mo 冊 . 1 16 ( a3 ) , aO move.w (a の ,d0 c 叩 . 響 # 20 , d0 80 beq ? 63 addq. 1 # 1 , ? PBX2 + 56 82 cmp. 響 # 22 , dO 83 addq. 1 # 1 , ? PBX2 + 60 c 叩 . 響 # 13 , ( ) 88 89 bne ? 72 addq. 1 # 1 , ? PBX2 + 64 mo 冊 . 1 16 ( a3 ) , a0 92 。叩 . 響 # 25 , (a の、 93 94 bne ? 72 addq. 1 # 1 , ? PBX2 + 68 move. 1 4 ( a の , -(sp) mo 冊 . 1 a4,-(sp) 99 Jsr —reg_mentioned_p addq. 響 # 8 , sp 100 tst. 1 d0 101 beq ? 72 102 addq. 1 # 1 , ? PBX2 + 72 104 nove. 1 16 ( a3 ) , a0 105 田 ove. 1 4 ( a の , al 106 c 叩 . 響 # 34 , (al) 107 108 bne ? 63 addq. 1 # 1 , ? PBX2 + 76 110 田 ove. 1 4 ( a4 ) , d2 111 c 叩 . 1 4 ( al ) , d2 112 113 bne ? 63 115 addq. 1 # 1 , ? PBX2 + 80 X68k 活用講座 143
C010r のメンバはすべて char て、すから , s izeof ( C010r ) は 3 , sizeof(buf) は 30 になりま 出力コードの改善とヘルプ 5 : 19 : / * 24 : { す。 2 : 3 : 4 : 7 : 10 : 11 : 12 : 14 : 15 : 16 : 20 : 22 : 23 : 24 : 25 : 26 : 28 : 29 : 30 : 31 : 2 : 3 : 4 : 5 : 7 : 8 : 9 : 11 : 13 : 14 : 19 : 20 : 22 : 25 : 26 : シフトを行うコードを , 16 ~ 24 ビットシ LiSt ー m68881 オプションバグ 1 : / * ー m68881 を指定すると fpa のレジスタをスタックから 復帰するときオフセットを間違う。ー m68881 を復活 させた時のエンバグでした。 fmovem. x fp2, -(sp) 1 ink a6, # 0 f00 : return X * y; for (i = 0 ; i く int i ; double y = 0.0 : double x = 0.0 : 8 : double foo(void) 6 : double dl(); 5 : double d0(); i 十十 ) move. 1 d3, ー (sp) fmovecr #$f, fp2 move. 1 (sp) + , dl move. 1 ー 16 ( a6 ) , d3 fmovem. x ー 16 ( a6 ) , fp2 * 間違い ! ! unlk a6 r ts List コンバイラの暴走 1 : / * -fforce-addr を指定してコンパイルするとバスエラー を起こしたり、コンパイルを中断したり etc. の不都合が foo *n = bugs() : 23 : void bug—test (int x, int の return f : f = &data[data—num + + ] : f00 *f ; 16 : inline f00 *bugs() 15 : / * inline 関数にしなければコンパイル OK です * / int data_num; 12 : f00 dataL50] : 10 : } f00 ; short dummyC3] : struct st *next; short x, y; typedef struct S t 起きる例 * / フトについて swap を用いて高速て、行うよう に変更しました。 GCC のようなビットフィ ールドを用いているソースについて有効て、 す。そのほかに環境変数 GCC OPTION に 、、 0 〃が設定してあると定数て、の変数設定を 少し最適化します。 それから , スタックフレームが 32K バイト を越えたら警告するようにしてあります。 「舍計なお世話」の方もおられるてしようが , 不用意に巨大な配列を自動変数に確保して 暴走させることがメモリに比較的制限のな い X68000 て、は多いようなのて、つけておきま また , gcc. x がヘルプファイルをサポート しました。ソースファイルを指定しないて とすればヘルプが表示されます。 スイッチの数が多いのて , 簡易版てはあり ますが , 普通に使う機能についてはヘルプ ファイルて、十分だと思います。ヘルプファ イルは gcc. x が存在するディレクトリから g cc. hlp というファイルを探して表示するだけ て、す。これが存在しない場合は何もせずに 終了します。 知っておくと便利なタグジャンプ X68000 に付属の ED. X を使う場合は , 環境 変数 MARIKO に文字、、 D 〃 , MARINA に E D. X, GCC OPTION にヾ E 〃を設定してお きます。工ラーがあると自動的にエデイタ が起動されるのて、 , 直したいエラー表示の 上にカーソルを移動して亘を押し , その 後を押します。画面が切り換わってソー スの該当位置にカーソルが飛びます。ソー スを修正して亘十回てセープしたら , 再 度自動的にコンパイルしなおします。 これをエラーがなくなるまて、繰り返せば いいのてす。プリプロセッサ段階てはこの 機能は働きません。 パソコン通信上て、もっとも数が多かった 質問は , 「新しい GCC ては疑似統合環境てタ グジャンプてきなくなった」というものてし た。工ラーメッセージのデフォルトが Nem X68k 活用講座 139
スタートアップ C 十十 。 9 実力養成講座 ったら , そのたびにソースコードのあちこ ちを細かくいじらなくてはならず , 完成に こぎつけるまて、に時間がかかってしまった て、しよう。 C 十十て、書いたおかげて、 , ほとんどデバッ グの必要もなく , 締め切りに間に合わせる ことがて、きました ただ , 今回のゲームに関していえば , せ っかく作り上げた住民やマップなどのクラ ス構造を , 「ゲーム本体」などという旧態依 然な方法てコントロールするのは , 「美しく ない」といわれても仕方のないところて、す。 て、すが , 何も C 十十を使うからといって , ど こまて、も C 十十らしいソースを書かなければ というわけて、はありません。楽 ならない , な方向に流れるとこうなったのて、す。 あくまて、も「 C 」十十なのて、すから , とき には , 堅苦しく考えず , C 十十のおいしいと ころをかじるだけても構いません。そうし ているうちに , 必要な知恵は勝手について きます。机上の理屈なんかどうて、もよいの て、す。 すべての言語機能は , 現実のプログラミ ングに奉仕するためにあるのて、すから。 気楽にいきましようよ。 「附録ディスク 細部にこだわるならば , まだ煮詰めるヘ き点がいくつか残っています。たとえば , 泥 棒と警官がすれ違ったらどうするか ( つかま んたことにするのが妥当て、しよう ) などなど。 これは , ディスクに譲ります。付録ディ スク収録のソースては , プレイバックと称 して , ゲームの終了時にマップを表示して , 泥棒と警官の動きを再現する仕掛けをつけ さて , 来月は・・ と , 意外と立派なゲームに仕上がってしま ています。これがないと , 何がなんだかわ 「もう 1 回ゲームはどうかなあ」 からないまま終わっちゃいかねないんて、す うかもしれません。 「うーん・・ 。ゲームもいいけど , カレーも また , 泥棒は一人だけという設定になっ ね」 ていますが , 何人もの泥棒が入り乱れるよ さらに発展させて , ゲーム中にもマップ 意味不明のオチとともに , 去っていく筆 うに改造してもおもしろいかもしれません。 を表示して , カーソルキーなどて警官を ( マ 者て、あった・ たいした手間は必要ないはずてす。 ップの中て ) 動かすようなものにしてみる LiSt ゲーム本体 1 void game() 〃マップ 3 Map map; 〃あなた 4 You you; 〃泥棒 Thief thief; 5 ″町の大時計 ? Clock clock; 6 7 8 / / 時計の針を進める 9 clock. tick() : cout くく clock くく endl; 〃時刻を表示 10 蔓皿P. notice(thief. position()); / / 泥棒が通った位置の住民にそれと知らせる 12 if (mapCyou. position()]. ask() = Success) { 13 cout くく endl くく”おめでとう。泥棒を見つけましたね日”くく endl; 14 / / 住民が発見を通報してくれた 15 break ; 16 do { / / あなたが移動 cout くく " どっちへ移動する ? [N,S,E,W] ”くく flush; 18 ) while (you. move(getchar() ) ト Success) thief. move() ; / / 泥棒が移動 20 if (thief. success()) { cout くく endl くく”残念 ! ! 泥棒はまんまと逃げてしまいました”くく endl; 22 23 break ; 24 コラム ちょっとしたテクニック しておけば警告は出なくなりますが , 本当 付録ディスク収録のソースリストで使っ のバグと見分けがつかなくなる危険があり たちょっとしたテクニックについて述べて ます。 おきます。 C 十十では簡単かっ安全な方法として関 T 「 avelle 「 : : move(cha 「 ) は cha 数定義で引数の名前を書かないという手 「型の引数を取るようになっていますが , こ があります。たとえば , れは class Thief では必要ありません ( 乱 void foo(cha 「 ) 数で移動方向を決めるため ) 。 Thief : : m ove ( cha 「 ) の引数はムダになってしまう puts( ” f00( ) uses no a 「 g. ” ) : わけですが , ここで TC 十十 /BC 十十は 「使われていない引数がある」という警告メ というように , 引数の名前を書かなければ , ッセージを出します。このような場合 , #p 警告を出さすにすみます。 「 agma a 「 gsused を関数の直前に指定 スタートアップ C 十十 115
のようにしてファイルをオープンしておく 必要がある。 やすい いるものよりもずっとわかりやすく , 使い ストリーム関数やファイル関数て、使われて 合の挙動などを指定するものて、あるが , C の のモードや , ファイルが存在しなかった場 る。これらは , ファイルをオープンする際 cess mode というふたつの引数を必要とす これは , ファイル名のほかに , io mode, ac が , もっとも利用頻度の高いものて、あろう。 m, access mode a) ・ File(const char * filename, iO mode ふたつめのコンストラクタ , 10 mode としては , 次の 5 個の定数が使用 て、きる ー 0 append appendonly readwrite writeonly readonly 読み込み専用 書き込み専用 読み書き両用 追加専用 読み込み , 追加両用 いずれも読んて、字の如して、 , 説明するのも 恥ずかしいくらいて、ある ()o append が読み 込み可能て、あることは , ちゃんとソースに 注釈がついている ) 。 C の記号定数て、行われ ているような変な省略はない もっとも , C におけるネーミングの省略 は , 識別子の長さに厳しい制限があった時 代の名残りて、あって , 別段 C 自体に罪はない のだが ( いまだに関数名や記号定数など , 省 略することを美徳と勘違いしている C プログ ラマは多いが , 最近のコンパイラの識別子 の長さを考えれば , ナンセンスとしかいいよ うがない ) 。 一方の access mode に指定可能な定数は , 以下の四つて、ある。 a createonly 新しくファイルを作る。ファイルがす て、に存在している場合はエラーとなる。 a create 新しくファイルを作る。ファイルがす て、に存在している場合はその内容を破 56 C MAGAZINE 1992 1 棄し , 新たなファイルとして扱う。 a useonly 既存のファイルを利用する。ファイル が存在しない場合はエラーとなる。 既存のファイルを利用する。ファイル が存在しない場合は新たに作成する。 し , create することも ( 当たり前だが ) 不可能 ロノし日 みき両用に設定することはて、きない てある。 なモードは io readonly と io writeonly のみ 御は引数 io mode による。ただし , 指定可能 し , 書き込みも可能て、ある。読み書きの制 字列を入れておいて読み出すこともて、きる のみを用意するものて、ある。バッフアに文 ファイルとの関連づけを行わず , バッファ 最後のコンストラクタは , ディスク上の 利て、ある。 めのオプジェクトを作ったりするのには便 るようにするものて、ある。標準入出力のた し , これを File 型のオプジェクトとして扱え ム関数て、使用される FILE * 型の変数を指定 5 番目のコンストラクタは , C のストリー 使用されるものて、はないだろう。 ode を指定せねばならない。それほど頻繁に 同様 , オープンしたときと矛盾しない io m ものて、ある。第 2 引数には , C の fd 叩 en() と ドル ) を指定して , インスタンスを生成する ンされているファイル記述子 ( ファイルハン 第 4 のコンストラクタは , すて、にオープ かもしれない こちらに慣れている人には扱いやすい もわかりやすいとはいいがたいものなのだ 、、 w クなどの文字を組み合わせた , お世辞に る。 fopen ( ) て、のアクセスモードは , 、、ドや などと同様の文字列によって行うものて、あ は , アクセスモードの指定を , C の fopen() ar* m) FiIe (const char * filename, const ch 第 3 のコンストラクタ 定義されている。 io mode と access mode は , Fmodes. h て、 て、ある。「データがたいした量て、はないの て、 , テンボラリファイルを使うのは懸命て、 ない」ような場合に , ファイルとの入出力を 前提としているクラスを「騙す」ような使い 方もて、きる。 これらのコンストラクタと対応する叩 en 関数が 4 種類用意されている。 List 9 て、は , 28 行目から 31 行目にあたるが , とくに説明 の必要はないて、あろう。それぞれ同じ引数 をもつコンストラクタの解説を参照してい ただきたい ( すて、にお察しの方もあろうかと 思うが , コンストラクタ達は , 内部て、それぞ れの open ( ) メソッドを使用している ) 。 さて , 次は FiIe クラスの入出力用メソッド をひととおり眺めてみたい ますは出力用のメソッドて、あるが , FiIe ク ラスて、は 4 種類が用意されている。 1 文字の出力を行うのが , 69 行目の put ( c har c) : て、あり , 文字列を出力するのが , 75 行目の put(constchar* s) ; て、ある。そ れぞれ , C のストリーム関数 fputc, fputs に 相当する。 このように , C 十十て、は , 同じ関数名て、あ っても , 引数の数や型に違いがあれば , 別 の関数としてきちんと識別される。 C におい てプログラマは , 関数名の衝突を避けるた めにたいへんな努力を要求され , それが C に おける難解な関数名のひとつの要因て、もあ った そういう無意味な努力は , C 十十において は大分解消されている ( なくなったわけて、は ない。クラス名の衝突には気を配らねばな らないし , 関数名以上に衝突の材科となり 得る記号定数については , いまだに野放し て、あるからだ ) 。 バイトサイズて、の出力を行うのが write ( v oid* x, int sz, int n) ; て、ある。これは , C の fwrite に相当する関数て、あり , 第 1 引数 ファイルとの入出力
て、ある。 自分て、積み木を作れる人ならば , どんど ん好みの形を作って , 積み木を増やしてい く手もある。自前のクラスライプラリを構 築するわけて、ある。しかし , そうて、ない人 は , どんな形が有用て、あるか判断がっかす , おろおろするばかりて、ある。原木をそのま ま削り出しても , 目的を達成することは可 能だ。が , 以後の作業が楽になるようなこ とは決してない 「クラスライプラリがない」のがどういう 状態か , ご理解いただけるだろうか ? ク ラスライプラリが完備されていれば , プロ グラマの「何をオプジェクトにすべきか」と いう悩みは半減・・・・・・いや , 10 分の 1 ぐらいに まて、なるだろう ( クラスライプラリの質にも よるが ) 。ゼロから生み出すのと , すて、にあ るものから選ぶのとて、は , 雲泥の差がある。 Smalltalk のユーザは , 「オプジェクトにす るってどういうこと ? 」という質間を発した りはしない。彼らの前にはすて、に完成され たオプジェクト ( クラス ) がごろごろしてお り , やることといえば , それを組み合わせ たり , 少々加工したりするだけなのだから。 そして , OOP とは本来 , かくあるべきもの て、ある。 54 C MAGAZINE 1992 1 CL のようにガチガチのオプジェクトワール あり , その機能はかなり強力て、ある。 NIH 準ライプラリとして添付されているものて、 ェクトの C 十十て、ある、℃ NUC 十十〃に標 た。このクラスライプラリは , GNU プロジ と注目を集めていたのが、、 libg 十十クて、あっ DOS などへの移植も容易なのて、はないか , そうしたなかて、 , 比較的汎用性が高く , 全体の標準となるに至ってはいない ながら , その規模や用途の関係上 , C 十十界 ールキット InterViews などて、ある。しかし alk のシステムクラス風の NIHCL や , X 用ツ ラスライプラリが出まわっていた。 SmaIIt 世界て、は , 比較的早い時期から C 十十用のク まったく存在しないわけて、はない。 UNIX の かといって , C 十十にクラスライプラリが ドを指向するものて、はなく , 個々のクラス の関連は比較的ゆるい。 C 十十向きの作りと 「誰か DOS にも移植してくれないかな」と いう期侍を持っていた筆者は , PC 用 GNU C 十十て、ある djgpp に libg 十十が標準添付さ れたことを知り , たいへんうれしく思った C において , UNIX 上て、標準的に使われる関 数が ( 非 ANSI のものて、も ) DOS 上の多くのコ ンパイラて、使用可能て、あるように , C の後継 言語と目される C 十十においても , UNIX と の互換性を得ることの意味は大きい。 C 十十 LiSt4 FILE* fp; / / _iobuf file pointer protected: friend class Filebuf; 1 : class File の言語仕様自体がまだ完全なものとはいえ ないだけに , 真の標準ライプラリの登場は ANSI の動向次第というところて、あるが , 1 ibg 十十の使用はおおいに促進されてしかる べきて、あろう。 本稿て、は , その前半のほとんどを使って , libg 十十に含まれる多くのクラスの中から「す ぐに使える利用価値の高いクラス」としてと くに FiIe クラスを取りあげ , その使用法につ いて解説する。ほかにも有用なクラスはた くさんあり , また組み合わせて使うことて、 さらなるパワーを発揮するクラスも多いの 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 12 : 13 : 14 : 15 : 17 : 18 : 19 : 20 : 21 : 22 : 23 : 24 : 25 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : 38 : 39 : 40 : 41 : 42 : ー 43 : 44 : 45 : 46 : char* nm; / / file name (dynamically allocated) char rw; / / 1 read; 2 = write; 3 readwr / / bit 2 ( 4 ) means read/write into string state—value state; / / —good/_eof/—fai l/—bad long stat; / / last read/write/.. return value void initialize(); VOid reinitialize(const char*),• char *readl ine ( int chunk number, char terminator) ; 16 : public: File(); Fi le(const char* fi lename, io_mode m, access_mode a) ; Fi le(const char* fi lename, const char* m) ; FiIe(int filedesc, io mode m); File(FILE* fileptr); FiIe(int sz, char* buf, io mode m); -File(); 26 : / / binding, rebinding, unbinding to physical files Fi le& open(const char* fi lename, io_mode m, access_mode a) ; File& open(const char* filename, const char* m) ; File& open(int filedesc, io_mode m); FiIe& open(FILE* fileptr); FiIe& close(); FiIe& remove(); / / class variable access int filedesc(); const char* name(); VOid setname(const char* newname) ; iocount() ; int rdstate() ; eof(); fail(); bad() : int int int int
なのて、 , ここて、は , 上記のキーワードの中 ュメント標準をかろうじて満たしているあ 一般に抽象データというと , プログラム から , C 十十の特徴的な点に焦点をしばり解 たりて、ある ( ただし , GNU C 十十は ARM を の対象となる情報から必要なものだけを抽 説する。 出して , 計算機上て、うまく表現したものを 完全に実装してはいない ) 。 ・抽象データとクラス 指す。たとえば , 「データ構造とアルゴリズ GNUC 十十の実装は , C 十十の進化を追 ・公開 , 保護 , 非公開 , フレンド ム」の話に現れるリスト構造 , ディクショナ うように ( そして , 時には新しい機能を試験 ・コンストラクタとディストラクタ リとか , 住所録プログラムて、の各人のレコ 的に付け加え ) 進化を続けてきた。 Ver. 1. ・型変換演算子 39 は , 多重継承や新しいリンケージ機構を ード表現とかを考えてもらえれば , それほ なおここて、は , ある程度の C の知識を前提 持っため , おおむね C 十十 2.0 相当て、ある。 ど間違っていないだろう。 しかし実装方法が異なる GNUC 十十て、は , にしている。 そして , 抽象データを使ったプログラム ほかの C 十十コンパイラ同様 , ドキュメント とは , プログラムの一部を抽象データとし に書かれていない細かな部分て、 A T&T てまとめることだと考えられる。それには , C 十十と非互換て、ある。 ・データ表現と実装は , 抽象データの中に そして GNUC 十十は , まだ未完成て、ある 隠してしまい , C 十十とクラスとは非常に関係深い。 C 十十 ( 現在テスト ) 。それゆえ , たとえば InterV ・抽象データをインタフェイス ( 関数群 ) に の前身て、ある C with CIasses がそうて、あっ iews のような C 十十 2.0 て、書かれたプログラ よって定義する たように , C 十十の設計は C にクラス機能を ムはそのままて、はコンパイルて、きず , 比較 ことを行わなければならない。そして , 抽 付加することから始まった。クラスは「抽象 的多くの修正を要求されることになる。つ 象データを組み立てて , プログラムを作成 データ」を実現するための機能て、ある。 まり GNU C 十十は , まだそれほど完成され する。抽象データは , インタフェイスて、定 た C 十十て、はないということて、ある ( 新しい GNU C 2.0 て、は C 十十の機能も取り込まれ ることになっているのて、 , その完成度に期 待しよう ) 。 GNU C 十十 (djgpp) を使うにあ . たって , このことを一応念頭に置いてほしい 抽象データとクラス List 1 struct point { public: point(void) ; point(void); double xcoord(void) ; double ycoord(void); double theta(void) ; double r(void); void move(double x, double y) ; void polar(double r, double theta) : private: 、よりっ 0 -4- 戸 0 6 ゥー 8 0 》 0 、 1 り 0 っ 0 1 人 1 人 1 よ 1 よ C 十十のポイント 初めに C 十十のキーワードをあげてみよ ・抽象データとクラス ・公開 , 保護 , 非公開 , フレンド ・コンストラクタとディストラクタ ・演算子多重定義 ・型変換演算子 ・継承と仮想関数 ・型検査と関数名多重定義 ・インライン関数 これらの話題は , よく C 十十の記事などて、 取りあげられていて , それほど目新しさは ないと思う。そして限られた誌面て、 , 体系 的に C 十十の仕様や機能を解説するのは困難 38 C MAGAZINE 1992 1 LlSt 1 人ワっ 0 4- 一 -0 6 叮ー 8 9 0 point v, *pv; double x V. xcoord; pv ニ new point; pv->polor(), の : delete pv; vr. move(x + 10 , の ;
皿Ⅸ System V ReIease 4.0 Ver. 3.0 は , ー Zp オプションて、変更て、きます。 ューザが使用することはないて、しよう。 n は , 1 , 2 , 4 のどれかの数値をとります。 #pragma pack (n) アライメントを 1 にすると , 記憶領域の効率 はもっともよくなりますが , 動作はもっと この pragma は , インテル 386 系て動く CI 5 に特有のものて、 , 構造体のメンバ割り付け も遅くなります。逆にアライメントを 4 にす のアライメントを指定します。デフォルト ると , 記憶領域の効率は悪くなりますが , 動作はもっとも速くなります。 は 4 になっていますが , コマンドラインから #pragma int t0 unsigned identifier ライプラリ関数の中には , 以前は int の返 り値を持っていたものが , C15 て、 unsigned 型 に変更になったものがあります。 -Xt モード において返り値を int 型として扱えるよう , コンパイラに通知します。この pragma も , TabIe 1 /usr/bin/cc のオプション一覧 オプションスイッチ [(tokens) ] —A name 内 assert ティレクテイプで定義するのと同様 コンバイラによって定義された asse は , 以下のニ ーっ system(unix) cpu(i386) machine(i386) で始まるもの以外のテフォルトのマクロ , asse ⅲ on を無効にする -B dynamic でダイナミックリンク , -B static で従来同様のスタティックリンクを行う プリプロセッサ命令行以外のすべてのコメントをコンバイラにそのまま渡す コンノヾイルのみでリンクしない マクロの定義 コンノヾイラによって定義された非標準のマクロは , 以下のふたっ i386 UnlX - dy でダイナミックリンク , - dn でスタティックリンク プリプロセスのみ行い , その結果を標準出力へ出力する 実行形式ではなく , ダイナミックリンク用シェアードオプジェクトを作成する sdb が参照できるシンホル情報をオプジェクトファイルに埋め込む ー g と一 0 は同時に指定できるが , オプティマイズについてよく知っている必要がある インクルードされたファイルを標準工ラー出力へ報告する インクルードファイルの格納されているティレクトリを指定する -K P ℃は , ホジションテイベンテントなオプジェクトを作成する -K minabi は , ダイナミックリンクを最小限にするライプラリをリンクするよう指示する ライプラリファイルの格納されているティレクトリを指定する リンクするライプラリを指定する オプティマイズを指定する 実行形式ファイルの名前を指定する ( テフォルト = a. out ) プリプロセスのみ実行し , . i という拡張子のファイルに書き出す プロファイラ用オプジェクトを作成する -0 y は , コンバイルのため起動されたツールに関する情報を , 出力ファイルに追加していく。ー 0 n は , 何も情報を書き出さない プロファイルに関するオプション。 - 可は , ゆ「 of によって各行が実行された回数をカウントできるコードを出力する。ー印は , ー 0 と 同時に指定できない。 -qp は , - p と同じ アセンプラ出力を . s ファイルに書き出す。ー 0 オプションが指定されていれば , オプティマイザも起動する マクロ名の削除 起動されるツールのバージョン情報を標準工ラー出力に書き出す lint-like な , より厳しい警告を出すよう指示する ANSI C 標準への準拠度を指示する Transition mode ANSI C mode -Xa Comformance mode -Xc [=tokens] —D name ヨ dir -K [P ℃ , minabi] -L dir ヨ name ー 0 ー 0 name ー 0 c —IJ name ¯V UNIX System V Release 4.0 Ver. 3.0 97
トが使えるように拡張してあったのて、すが , これがバグっていました。 List 2 の、、ソクの文字の 2 バイト目は、、 \ ク のコードて、あるために , 行継続と認識して 次の行の、、 f00 ( ) ; 〃が消失してしまいま す。なお , この、、 P クは gcc ccl. x の制御文 字と競合していましたのて、 , 、、十〃に変更さ れています。 MS-DOS などの一部のコンパイラてソ / 〃 をコメントとして扱ったソースのコンパイ ルに役に立って、しよう。 コード生成のバグ X68000 版 GCC て、は 32 ビット乗算命令を持 たない 68000 のために , 計算式の一方が定数 て、ある場合 , すべて shift, add, sub 命令を用 いて計算を行います。これによって構造体 の配列や多次元配列のアクセスがかなり改 善されるのてすが , このインプリメントが 十分て、なかったために List 3 のようなバグが 発生してしまいました。 ループ内部て、計算される i * 7 は ,bufC] [ ] をアクセスするための配列アドレス計算 を行う際の一連の shift, add の一部分て計算 結果を得ることが可能て、す。ところが -fstr ength-reduce を指定すると , この配列アド レス計算が最適化され , 削除されてしまい ます。この結果 , 計算途中結果を用いてい た i * 7 の結果がなくなってしまうといった 14 : ) 16 : / * 22 : ? 9 : 26 : ? 8 : 39 : * / コード生成のバグ LiSt ポートしていますが , これを X68000 版に復 活 ( ソースから削除してありました ) させる 際に List 4 のようなエンバグが起きてしまい ました。 なお , gcc. x は一 m68881 が指定されるとア センプラの前に fppp. x を起動します。て、すか ら , fppp. x がない場合には意味がありませ ん。ご注意ください。また , ー m68881 を指定 〃が #define され するとヾ HAVE68881 コンバイラの暴走 先ほどの定数乗法展開の処理がほかのバ グを持っていたため , List 5 のようなソース をコンノヾイルすると gcc ccl. x がノヾスエラー を起こしたり , 途中て、コンパイルを放棄し たりしました。 ドキュメント化されていない 追加機能と補足説明 このほかにいくっかの機能と改良が加え られています。また , 知っておくと便利な 機能も紹介します。 -fst 「 uct-st 「 ict-align List 6 の構造体 C010r は , 普通にコンパイ ルすると 1 構造体て 4 バイトのメモリが確保 され , sizeof ( C010r ) は 4 になります。て、す が , この C010r のメンバはすべて char て、 , の場合は厳密に偶数に境界整合の必要はあ りません。このようなときに -fstruct-stric t-align を指定した場合は , すべてのメンバ の境界整合条件のもっとも厳しいものに合 わせます。 1 : / * -fstrength-reduce を指定してあると、以下のような 配列添え字かのアドレス計算とループ内部での演算に 共通部分式があると誤ったコードを生成していた。 GCC のオリジナルバグではありません。 * / 6 : int bufC7][7]; 8 : bug0() int i, j,t for (i = 0 ; i く 7 : i + + ) for (j = 0 ; j く 7 : j + + ) buf[i]Cj] = 17 : —bug0 : 15 : 13 : 12 : 11 : 10 : 4 : 3 : 2 : バグて、した。 138 C M AGAZIN 1992 1 ー E68881 オプションバグ すが ) 。もともと , GCC はコプロセッサをサ るらしいて、す。私は使ったことがないのて、 とがて、きます ( その威力は凄まじいものがあ 用いて浮動小数点演算を高速に実行するこ 所持している場合は , ー m68881 オプションを このフリーウェアとコプロセッサポードを 換える fppp. x [ 注 1 ] というものがあります。 を直接ドライプする命令シーケンスに置き きない 68881 命令を , X68000 のコプロセッサ X68000 のフリーウェアに 68000 て、は実行て、 18 : 19 : 20 : 23 : 24 : 25 : 28 : 29 : 31 : 32 : 33 : 34 : 35 : 36 : 38 : movem. 1 d3/d4/d5, -(sp) moveq. 1 # 0 , d3 lea _buf, al moveq. 1 # 0 , d2 move. 1 d2, d0 moveq. 1 # 6 , dl lea 24 ( al , d0. 1 ) , a0 move. 1 d4, (a の subq. 響 # 4 , a0 dbra dl, ? 8 ext. 1 dl moveq. 1 # 28 , d5 add. 1 d5, d2 addq. 1 # 1 , d3 moveq. 1 # 6 , d5 cmp. 1 d3, d5 bge ? 9 movem. 1 ( (p) + , d3/d4/d5 rtS * d4 に何も値を入れてない ! !