新 MS ー DOS プロクラミンク入門 C プログラマのための TabIe 9 フォントノヾターンの取得 ( FM ー TOWNS ) フォントノヾターンの取得 引数 A H = 07 h D H = 横のドット数 DL = 縦のドット数 半角フォント DX = 0808h : 8 x 8 半角フォント DX = 081 Oh . 8 x 16 全角フォント DX = 1 01 Oh : 16 X 16 BX = 』 S コード AN K コード : B H = 0 , B L = A N K コード 全角コード : B H = 2 バイト目 , B L = 1 バイト目 DS:SI = 文字バターンのイメージバッフアアドレス INT 91h 返り値 AL = 00h : 正常終了 AL = 02h : 指定された文字コードに対するドット数か異常 機能 BX レジスタで指定した全角または半角コードのフォントバターンを返す 文字バターンのイメージバッフア内の格納順序は以下のようになる 8 X 8 8 x 16 隙間なく印字するために罫線部分を Fig. 2 の ように横方向に引き延ばしています。縦方 向に隙間なく印字するためには , まず Fig. 3 のように 16 ドットを 24 ドットに拡張して印 字します。そして , 1 文字の高さぶん改行し て次の印字位置まて、の隙間に縦罫線を隙間 分だけ印字します。したがって , スイッチ ー k を指定すると 1 行を印字するのに 2 回に分 けて印字する感じになります。 プリンタの制御コード 本ユーティリティて、使用しているプリン タの制御コードを TabIe 10 に示します。 動作確認 動作確認は PC ー 9801 シリーズと DOS/V マ シンて、行っています。 J ー 3100 シリーズて、も 動作していましたが , 紹介するに当たって 書き直しているため , すべてのオプション 16 x 16 31 32 Fig. 2 ノヾソコンのフォントとプリンタの 24 ピンピットイメージ 7 6 5 4 3 2 1 0 罫線横拡張 7 6 5 4 3 2 1 0 ・〇〇〇〇〇〇〇 〇〇〇 〇〇〇〇〇〇〇 オフセット十 00 ・〇〇〇〇〇〇〇 〇〇〇 十 02 〇〇〇〇〇〇〇 ・〇〇〇〇〇〇〇 〇〇〇 十 04 〇〇〇〇〇〇〇 ・〇〇〇〇〇〇〇 〇〇〇 〇〇〇〇〇〇〇 十 06 〇〇〇 ・〇〇〇〇〇〇〇 十 08 〇〇〇〇〇〇〇 ・〇〇〇〇〇〇〇 〇〇〇 〇〇〇〇〇〇〇 十 OA ・〇〇〇〇〇〇〇 〇〇〇 〇〇〇〇〇〇〇 十 OC 十 OE 十 1 0 十 1 2 〇〇〇〇〇〇〇 ・〇〇〇〇〇〇〇 〇〇〇 〇〇〇〇〇〇〇 十 14 〇〇〇 ・〇〇〇〇〇〇〇 〇〇〇〇〇〇〇 〇〇〇 十 1 6 ・〇〇〇〇〇〇〇 〇〇〇〇〇〇〇 〇〇〇 十 1 8 ・〇〇〇〇〇〇〇 〇〇〇〇〇〇〇 〇〇〇 十 1 A ・〇〇〇〇〇〇〇 〇〇〇 〇〇〇〇〇〇〇 十 1 C ・〇〇〇〇〇〇〇 〇〇〇 十 1 E 〇〇〇〇〇〇〇 ↓ プリンタでは この列から 順に印字する 罫線の横拡張ではこの列を 必要なドット数だけコピーする 新 MS-DOS プログラミング入門 89
TabIe 4 フォントノヾターンの取得 ( pc ー 9801 シリーズ ) TabIe 7 文字バターンの読み取り (DOS/V) フォントバターンの取得 文字ノヾターンの読み取り 引数 AH = 14h 引数 AX 1800h DX = 読み出すフォントの』 S コード : 予約済 B H = 00 h BX:CX = フォントバターンを読み出すバッフアアドレス : フォントの選択 ( 文字セット 0 ) B L = 00h CX = 全角 : シフト』 S コード (CH: 1 バイト目 , CL : 2 ノヾイト目 ) 2 バイトフォントノヾターンノヾッファ ( 8 , 16 , 32 ノヾイト ) = 半角 : C H = 0 , C L = A N K コード 制御域 DX = 0810h : 8X16 ドットの半角文字ノヾターン INT 18h 8X19 ドット半角文字ノヾターン = 0813h . 1010h : 16X16 ドット全角文字ノヾターン 返り値 なし 1818h : 24X24 ドット全角文字パターン 8 X 8 ドットの A N K フォントは D H = 0 て読み出し , 8 X 16 ドットの 機能 ES:SI = 文字ノヾターンのイメージバッフアアドレス ANK フォントは DH = 80h で読み出す。 16X16 ドットの全角フォ INT 10h ントは DH , DL レジスタに』 S コードを指定する。呼び出し後は BX : CX 十 0 に縦のドット数 / 8 , BX:CX 十 1 に横のドット数 / 8 がセッ 返り値 AL = 00h : 正常終了 トされ BX : CX 十 2 以降にフォントのドットノヾターンがセットされる AL 01h—FFh : 工ラー 読み出しコード制御域 ドット数 文字タイプ ノヾッフアサイズ 機能 CX レジスタで指定した全角または半角コードのフォントノヾターンを 横 x 縦 D H DL 十 1 , 十 0 返す文字パターンのイメージバッフア内の格納順序は以下のように ANK ( 高解像度 ) 7 X 13 80h ANK 2 十 16 なる AN K ( 標準 ) 6 X 8 00h ANK 1 2 十 8 全角 2 ノヾイト J 旧コード 15 x 16 2 十 32 8 x 16 NECJIS コード 半角 2 バイト 7 x 16 1 , 2 8X19 1 / 4 角 2 バイト 00h ANK 6 >< 8 2 十 8 フォントバターンノヾッフア内の格納順序は以下のようになる 8 x 18 8 x 16 ↓ 16 X 16 24X24 1 一 B 圏 0 16 X 16 〕 B 品 0 31 32 46 47 48 TabIe 8 文字フォントの読み取り ( AX マシン ) 文字フォントの読み取り 引数 AH = 51h AL = 01h ES : B P = 読み出しバッファ先頭アドレス DX = 読み出す文字コード ( シフト』 S ) BH = 文字の横のビット数 B L = 文字の縦のピット数 BX = 0808h : 8 X 8 ドット AN フォント = 080e h : 8 X 14 ドット AN フォント = 0813 h : 8 x 19 ドット AN K フォント 1 01 Oh : 16 x 16 ドット全角フォント INT 10h 返り値 AL = 0 正常に読み出した AL 1 読み出すことができなかった 機能 ES : BP レジスタで指定するバッフアに DX レジスタで指定する文 字フォントテータを読み取る ES: BP レジスタで指定される文字フォントテープル内の格納順序 は以下のようになる 8 x 19 31 32 TabIe 5 漢字 ROM アドレスの取得 ( J ー 3100 シリーズ MS-DOS 31 ) 漢字 ROM アドレスの取得 引数 AH = 03h シフト』 S 1 6 X 1 6 ドットフォント AL = 00h = 01 h 1 6 x 1 6 ドットフォント = 02h シフト』 S 24 X 24 ドットフォント = 03h 24 x 24 ドットフォント DX = 漢字コード ( シフト』 S コードまたは J 旧コード ) INT 60h ノヾンク番号 ( 0 ~ 15 ) 返り値 AL ES:SI = フォントノヾターンのアドレス 機能 DX レジスタで指定した漢字コードの漢字 ROM のノヾンク番号とフ オントノヾターンのアドレスを取得する TabIe 6 英数字フォントのアドレスの取得 ( J ー 3100 シリーズ MS-DOS 3.1 ) 英数字フォントのアドレスの取得 引数 AH 1 Oh AL = 00h INT 60h 返り値 AL FFh : 工ラー ES:BX = フォントテープルのアドレス 英数字 ( 8X16 ドット ) のフォントテープルのアドレスを返す 機能 フォントテープルは英語モード用のため当″は、、 \ ″になる 16 X 16 16 32 88 C MAGAZINE 1992 9
C プログラマのための h) が定義されています。これに対応しない TabIe 2 新』 S コードの罫線 9 A D E F とタブの位置合わせが狂ってきます。とく 5 6 7 8 B C JIS 0 1 2 3 4 5 6 7 8 9 B C D シフト』 S E F 1 2 3 4 A 0 に , 半角罫線て、表を作成してあるとまとも 亠十 丁 2820 849E な表が印刷て、きません。本ューティリティ 2830 84AE て、は半角漢字の場合には 1 カラム分しか進め 2840 84BE ないため , 半角罫線を使った表もきれいに TabIe 3 NEC 特殊漢字 印刷て、きます。 JIS シフト』 S 0 1 2 3 4 6 7 5 8 9 A B C D E F また , ESC/P プリンタは半角漢字のフォ 2 9 20 85 3 F 十 ントを持っていないのて、 , ビットイメージ 2930 1 2 3 4 5 6 7 8 854F 0 9 2940 A B C D E F G M N 0 85 5 F H J K L て出力するモード ( スイッチ -j3) を持ってい Z P 0 R S T U V W X 2 9 50 85 6 F Y ます (ESC/P と PR ー 201H の両方に対応して c d e f 2 9 60 8580 a b g h k m n 0 いる ESC/P プリンタて、は半角漢字のフォン z 2 9 70 85 9 0 S t P q u V W x y トも持っているようて、すが , 使ったことが 2A20 85 9 E ヲ オ ヤ ア イ 工 ウ ツ ユ ヨ ないため確かて、はありません ) 。 ウ 2A30 85AE アイ 工オカキク ケ ス セ コ サ シ ソ PC ー 9801 シリーズ以外て、はパソコン本体か 丁 ト 2 A40 タ ナ ヌ ネ へホ 85 B E チ ノ 八 ヒ 、ン フ マ ム モ ヤ 2A50 85CE メ フ リ ル レ ン ユ ヨ ロ ワ らフォントパターンを読み出せないため , ヶ ヴガギグケ ゴザジズゼゾ ヰ 2A60 85DE ワ カ 現バージョンて、は NEC 特殊漢字をビットイ ダチ ピ ピプ ペポポ ァ ド ババ 2A70 85 E E べ メージて、印字させることはて、きません。 DO 2B20 8 6 3 F S / V マシンて、は PC ー 9801 シリーズのフォント L L 2B30 864F に置き換えるユーティリティがあるようて、 2B40 86 5 F 2 B 50 86 6 F すが , 筆者は入手していないため対応して 十十十十十十十十十十十十十十十十 2 B 60 8680 いません。 2 B 70 8690 ・フォントバターンの取得 86 9 E 2C20 86AE 2C30 ビットイメージて、出力するにはパソコン 全角罫線 86 B E 2C40 ユー」一一亠 - 上 . ユー—L 亠 が持っているフォントパターンを読み出さ 2C50 十十十十十十十十十十十十十十十十 86DE 2C60 なくてはいけません。フォントパターンを 2C70 86 E E 取得するためのファンクションを Table 4 , ①②③④⑤⑥⑦⑧⑨⑩⑩⑩⑩⑩⑩ 2D20 87 3 F Table 5 , TabIe 6 , TabIe 7 , TabIe 8 , ⑩⑩⑩⑩ ⑩ 2D30 87 4 F I Ⅱ Ⅲ Ⅳ V Ⅵ Ⅶ Ⅷ Ⅸ X Table 9 に示します。フォントパターンは セン セ外 バー ッ カロ ド 2D40 87 5 F ーリ ン ル ル ト ロ 全角 : 16 >< 16 ドットフォント cc ⅲ 2D50 87 6 F 跚 mg ①①① @ 株有代明治大正昭和 8780 2D60 半角 : 8 x 16 ドットフォント 2 工 f 8790 2D70 n U 亠 Z を読み出しています。全角て、 24 x 24 ドット と新 JIS コード ( 1983 年式 ) と旧 JIS コード ( 1 表はそのまま JIS コードて、出力すると罫線が フォントが読み出せる機種もありますが , 978 年式 ) があります。 PC ー 9801 シリーズて、は 印字されないため , 新 JIS コードの罫線 ( Ta プログラムを簡単にするために 16 x 16 ドッ ble 2 ) に変換しないといけません。しかし , 旧 JIS コードをベースにして独自に罫線コー トフォントに統一しています。 NEC 漢字の罫線コードのほうが種類が多い ドなどの一部を追加したコードを採用して ビットイメージて、出力するときには読み ため , 変換て、きない罫線がて、てきます。 います。一方 , ほかのパソコン ( J ー 3100 シリ 取ったフォントパターンをプリンタのビッ ーズ , AX マシン , FM-TOWNS など ) て、は トイメージ用に変換します。プリンタは 8 ヒ。 れを印字するにはスイッチ -j3 を指定してビ ットイメージて、出力します。 新 JIS コードをベースにして空きェリアに独 ンまたは 24 ヒ。ンを 1 列ずっ左から右に印字 自のコードを追加しています。今回対象と していきますが , パソコンのフォントパタ PC -9801 シリーズの 半角漢字への対応 するエプソンの ESC/P プリンタも ESC/P モ ーンは TabIe 4 などに示したようになってい PC ー 9801 シリーズて、は 2 バイト半角の漢字 ますから , 一捻りしないといけません。 ードて、は新 JIS コードを採用しています。 展開するとき , 罫線に関しては横方向に したがって , PC ー 9801 シリーズて、作成した コード (Table 3 , シフト JIS : 8540h ~ 869E 半角漢字 新 MS-DOS プログラミング入門 87
PC ー 9801 シリーズて、一 j3 を指定すると半角 罫線などの PC ー 9801 シリーズ独自の半角漢字 ( 1 の -d を印字て、きます。 ビットイメージモードのドット数を指定 -d9 -d8 します。 ( 16X24 ) ー d24 : 24 ピンビットイメージモード ( 16X16 ) ー d16 : 24 ピンビットイメージモード : 9 ピンビットイメージモード : 8 ピンビットイメージモード 出力します。 デフォルトて、は漢字コード ( JIS コード ) て、 指定て、き , 省略値は 66 ( 66 行 x ( 1 / 6 ) インチ = 行単位ページ長を指定します。 1 ~ 127 が ( 11 ) -p ポートすることは難しくないて、しよう。 ティを拡張して IBM - PC 用のプリンタをサ カタカナは印字て、きません ) 。本ユーティリ が印字て、きるかもしれません ( ただし , 半角 リンタが標準なのて、 , ー d9 を指定すれば漢字 せんが , IBM-PC 用のプリンタは ESC/P プ タて、は印字て、きません。確認はしておりま いるため , MP-80 などの初期の 9 ヒ。ンプリン して ESC/P 09 ー 81 の制御コードを使用して 確認は行っていません。 ESC / P のレベルと は RP ー 80 がすて、に手元になかったため , 動作 すが , 本ユーティリティを作成したときに ーティリティて、サポートしていたモードて、 -d9 は本ユーティリティの前身になったユ ードて、す。 あげることがて、きるため , サポートしたモ 極端に遅くなりますが , 縮小度をもっとも イメージて、出力します。ー d16 は印字速度が ANK コード ( 英数字カタカナ ) ともにビット メージて、出力しますが一 d16 は漢字コードと -d8, -d9, ー d24 は漢字コードをビットイ TabIe 1 1 行に印字可能な文字数 ( 半角単位 : キャラクタ / ライン ) スイッチ - d24 -d 1 6 -d8 -d9 ー「 d24 ー「 dl 6 - 「 d8 ー「 d9 15 インチ 1 63 1 63 204 1 63 272 272 306 272 10 インチ 108 108 136 108 180 180 204 180 A4 99 99 124 99 1 64 1 64 186 1 64 縦罫線連続 スイッチ -k なし ヨ 74 ヨ 74 ヨ 74 不明 ヨ 74 ヨ 74 不明 11 インチ ) て、す。 A4 11 . 5 インチ 12 インチ ( 12 ) ー ー P69 or ー P70 ー P69 ー P72 のデフォルト値は 62 行てす。 のファイルて、は 4 , これら以外のファイルが フォルト値は , 拡張子が . c ? ? , . h, . k ? ? タブ刻み幅を指定します。タブ刻み幅デ ( 14 ) -t フォルト値は 163 カラムて、す。 1 行当たりの桁数を指定します。桁数のデ ( 13 ) -c 77 行 ( ー d16 の場合 111 行 ) としています。 るときに使っています。 1 ページ最大行数は ます。 1 ページ単位のファイル原稿を印字す する前に行数を数えて改行ピッチを計算し ー 10 は非公開のスイッチて指定すると出力 ( 15 ) -h ー ? 8 となります。 手を抜いています。 からのファイル入力は使うことがないため , 能しません。対応は可能て、すが , 標準入力 判定て、標準入力を読んて、いるためうまく機 皿 + 囮による中断機能と起動時の機種 この機能は不完全て、す。十回 , 標準入力から入力するモードになりますが , ファイル名が指定されなかったときは , 皿十囮を入力してください。 て、起動したときは皿十回または -TOWNS て、プリンタケープルを接続しない グラムを終了します OIBM- ・ PC 互換機や FM または皿十囮のキー入力があるとプロ ードも使用可能て、す。印字中に皿十回 ファイル名は複数指定て、き , ワイルドカ 簡単なヘルプメッセージを表示します。 1 行に印字可能な文字数を TabIe 1 に示し ます。縮小モードは大きな表を 1 枚の紙に印 刷するときに便利て、す。 印刷ユーティリティ vp の使用例 ( 1 ) vp ー f 可 3 ワ 0C108 file 10 インチの用紙に行番号をつけて印字す る例て、す。 JIS 第一水準と JIS 第二水準の漢 字コードは JIS コードて、出力しますが , NE C 特殊漢字はビットイメージて、出力します。 ( 2 ) vp -rfnj3170c180 file 10 インチの用紙に行番号をつけて縮小印 字する例て、す。 ( 3 ) vp -rfnj3170c132d9 file 9 ヒ。ンプリンタの RP ー 80 用の例て、す。 ( 4 ) vp ー 0fj3p6 引 0c99 file A4 用紙に 1 ページずっ印字する例て、す。 ( 5 ) vp ー rofj3p6 引 0C165 file A4 用紙に 1 ページずつ縮小印字する例て、 す。 印刷ユーティリティ vp の説明 機種依存部の判定と 1 バイト出力 機種依存部の判定とプリンタ 1 バイト出力 に関しては 1992 年 5 月号の特集て、説明してい ますから , 今回は省略します。 ・罫線コードについて パソコンの漢字コードには大きく分ける 1 ページ当たりの行数を指定します。行数 86 C MAGAZINE 1992 9
ll 川 a ⅱな om 町ⅱ計 Makers マイクロソフト MS-C Ver. 7.0 前回に引き続き , MS - C の最新バ ングガイド』第 2 章参照 ) 。 text プラグマの代わりになりま の使い方に誤りがあるプログラム ージョン Microsoft C/C 十十 Dev p-code す。 は MS-CVer. 7.0 て、はコンパイル elopment System for Windows プログラムまたはその一部を p- セグメント名の最後に TEXT が て、きません。 version 7.0 ( 英語版 , 以下 MS-C code にコンパイルすると , 一般に つくとき , コンパイラはこのセグ ポインタ based ( (_segment) Ver. 7.0 ) について説明いたしま 4 分の 1 ぐらいにコードのサイズを メントをデータセグメントて、はな If ) に変換てきるのは , 左辺値 す。 小さくて、きます。 く , コードセグメントに変換しま のみて、す。代入式の右辺は左辺の なお , 今回の情報は , IBM PC ま プラグマ す (Fig. 3 ) 。 MS-C Ver. 6.0 て、は , 型に変換されるのて , based(( たは互換機をご使用のユーザのみ autO inline, code seg, data s MY TEXT はデータセグメントに segment) self) ポインタに対し 利用可能てす。また , 今回の情報 eg, hdrstop, inline depth, inlin なりますが , MS-C Ver. 7.0 は , て代入を行うときは , 明示的なキ は , 将来発売される日本語版て、は e recursion, native caller, war MY TEXT をコードセグメントに ャストを使う必要があります。た 必ずしも有効とはかぎりません。 ning などのプラグマが新しく用意 変換します。 とえば ,Fig. 1 ( a ) て、は , ( b ) のよう 今回はとくに , MS-CVer. 6.0 されています。一方 , same_seg, ランタイムライプラリ関数 に解釈されます。しかし , 式 1(Fi と MS-CVer. 7.0 のコンノヾイラの 10 叩ー opt がサポートされなくなっ MS-CVer. 7.0 て、は , 仮想メモ g. 1 (a) のアミの部分 ) はセグメン 機能の違いについて説明します。 たのて、 , それぞれ based キーワー リをサポートする関数が追加され トを持たないのて、 , これは無効に MS-CVer. 7.0 て、は , いくつか ド , optimize プラグマを代用して ています。 なります。オフセット 1 をこの ba の機能が追加 , 削除 , 変更されて ください フ変数 osmajor, osminor, OS sed ポインタに置くには , Fig. 1 の います。そのうちいくつかは , AN インライン関数 version, osmode に加えて , 変数 (c) のように based (void) ポイン SI の C 言語の規格に対応するため inline キーワードは , 関数定義 cpumode が提供されています。 タにキャストする必要があります。 の変更て、す。 内のコードを , それぞれの関数呼 の変数は REAL MODE, または 同様に , Fig. 2 の ( a ) のようなステ 旧バージョンの MS ー C て、作成 , コ び出して、置き換えるようにコンパ PROTECT MODE のどちらかを ートメントて、 , ui の内容を base ンパイルしたコードに影響を与え イラに指示します。コードの置き 返し , 現在のプロセスモードを示 d ( ( segment) self) ポインタに るような変更点はほとんどありま 換えはコンパイラの判断て行いま します。 移動するには , Fig. 2 の ( b ) のよう せんが , 場合によっては既存のコ す。 inline キーワードは , それぞ 関数 fatexit と fonexit を使う にします。また , MS-CVer. 7.0 ードを変更または修正する必要が れの関数に対して個別に指定しま と , プログラムの終了時にモデル ては , 関数を特定のセグメントに あります。 す。 /Ob2 コマンドラインオプション に依存しない処理を実行て、きます。 割り当てる必要があるときに , 関 を指定すると , てきるだけ多くのイ また , ライプラリ関数 snprintf と 数をセグメント定数をベースとし 新しい機能 ンライン関数を作成することによ vsnprintf を使うと , ノヾッフアに書 て宣言て、きます。この機能は a110C まず , MS-C Ver. 7.0 て、新しく ってコードを最適化します。 inl based ( void ) ポインタへのキャスト ( その 1 ) 追加された機能について説明しま ine キーワード ( および / Ze オプショ (a) int _based ( ( segment) self) * piself , す。 ンを使ってコンパイルしていると piself = 国 : (b) (int based(( segment) self)) 1 ・ piself C 十十のサポート きの inline キーワード ) は ,MS-CV (c) (int based(void) * ) 1 ・ piself MS-C Ver. 7.0 て、提供されてい er. 7.0 の新しいキーワードてす。 組み込み関数 る C 十十コンパイラは Margaret A. Fig. 2 based ( void ) ポインタへのキャスト ( その 2 ) 組み込み関数を最適化するコマ EIIis, Bj arne Stroustrup 著 fAnn (a) unsigned short us . p iself ンドラインオプション (/Oi) または otated C 十十 Reference 』に記述 (int based(void) * ) ui . (b) piself intrinsic プラグマを使うと , コンノヾ されているプログラミング言語 コードセグメントに変換される例 Fig. 3 イラは関数のインラインコードを C 十十を実現します。 void functl ( ) 作成します。 プリコンバイルヘッダファイル static char based( segname("MY TEXT")) a 「「 [ ] A string*n based キーワードによる関数の割 プリコンパイルヘッダファイル を使うと , C および C 十十プログラ り当て Fig. 4 宣言における const 属性 ムのコンパイル時間を短縮て、きま MS-CVer. 6.0 コンノヾイラのノヾ typedef const int CI. / * lllegal * / const Cli . す ( 製品に添付される「プログラミ グ修正のため , based キーワード / * lllegal! * / 150 C MAGAZINE 1992 9
日聞 C++ 3.1 特集。 Borland 3 』研究 これがオプジェクト and のクラスライプラリだけのことはあっ がたかったのて、すが , おそらくライセンス供与されているのて、し て , もともとかなり読みやすいし , プログ とリアルに感じる 指向のパワーなんだな , よフ。このデノヾッグカーネルは当然ほかの ことがて、きるライプラリて、す。 ラムの流れがわかりやすく , 拡張も容易て、 3 製品にも含まれています。それぞれに Tur BC 十十 3.1 と BC 十十 & AFX3.1 のパッケ す。 ProtoGen て、骨組みを作って ObjectWin bo Debugger for Windows がバンドルされ ージに FREE ProtoGen というシールが貼っ dows にコードを足していくことて、かなり安 ているからて、す。 windows. h も新しいものが含まれていま てあり , 「これを貼ってレジストしてくれれ 直に Windows プログラミングが行えます。 す。さらに , 古い 3.0 用のヘッダファイル ば製品を送付しますよ」とかいうやっか , と この安易な方法がくせになりそうて、す。 も , win30. h とリネームされて入っているの 思ってパッケージを開けたら Prot0Gen その ProtoGen は当然日本語に対応していません て、 , Windows 3.0 向けのアプリケーション が , ObjectWindows のコードを生成するの ものがマニュアルごと入っていました。 Pr を万が一作る場合にも対応て、きます。 otoGen は Borland の製品て、はないのて、 , て、すから , PC ー 9801 版の BC 十十に持ってき また , TP/Win1.5 には Amish という仮想 れもアメリカ / カナダだけのキャンペーンな てメニューリソースやダイアログをいじれ スクリーンユーティリティがおまけて、つい ば利用て、きます。 のて、しよう。 ていました (Fig. 27 ) 。これもキャンペーン ProtoGen は CASE/W と同じように , Wi とくに BorIand C 十十の ObjectWindows なのて、しよう。 ndows アプリケーションのインタフェイス部 はダイナミックメッセーシディスパッチと ProtoGen は日本の BorIand から買えると 分をビジュアルに作成してソースコードを いう独自の機能を持っていて , 特定のメッ いうことて、すが , Amish は扱っていないそ セージに応答する関数を定義するだけて、処 吐き出す Case ツールて、す。 CASE / W とのい うて、す。秋葉原あたりて、売っていそうな気 ちばん大きな違いは , C 十十のクラスライプ 理の分岐がて、きます。 Windows からメッセ ージが送られてくると , 自動的に C 十十のメ はしますが・・ ラリ , ObjectWindows のコードを直接生成 ンバ関数呼び出しに変換してくれます。定 BC 十十 &AFX には ,API のリファレンス て、きるところて、す。もちろん C のコードも生 が 3 分冊てパッケージに含まれています。 義がされてない場合はデフォルトの処理を 成て、きます。実際に試してみるとなかなか とうりて、重くなったと思いました。この中 行ってくれるし , めんどうな記述も必要あ おもしろいものて、した。 ProtoGen のウイン りません。実にオプジェクト指向らしいア には当然 3.1 て、拡張された OLE やコモンダイ ドウの中にある , 生成されるターゲットの アログなどに関する記述が含まれています。 プローチだといえるて、しよう。 アプリケーションにメニューやダイアログ ProtoGen の追加はおまけとして , 付属の をマウスて、選んて、張り付けていくと , すっ Windows Ver. 3.1 マニュアルにもかなり手が加えられている きりとしてわかりやすい ObjectWindows の 対応の新機能 ようて、す。バーションナンバも 3.1 に変更さ コードがコメントつきて、生成されるのて、す。 これはとても楽て、す。 れています 0TurboDebugger のノヾージョン ObjectWindows のコードは , オプジェク は 3.0 のままて、すが , 当然デバッグカーネル Windows Ver. 3.1 て、は OLE (Object Lin は 3.1 対応に変更されていました。これは ト指向技術に関しては一日の長がある B 。 rl king&Embedding) が OS レベルて、サポート Fig. 25 BC + 十 &AFX3.1 Fig. 26 BC 十十 3.1 のアイコン 要 Eilc 0 ions 、 Yindow BORLÅND C + + &APPLICATION FRAMEWORKS FORWINDOWSAND DOS 材日 BORLAND 0 + & A 10 砂にを岱 緲 W 愛 0 し、、辞 5 田 , B 0 ー A N 0 特集 BorIand C 十十 Ver. 3.0 研究 57
オプジェクトを作って , オプジェクトを関 数の中から , 関数の外のそのテンボラリオ プジェクトへ コピーコンストラクタを 使って一一一コヒ。ーします。また , 式を評価 していくときも , テンボラリオプジェクト を作ることがあります。 A 十 B 十 C ; 上の式は , ューザ定義型 f00 のオプジェク ト A, B, C に , f00 型のオプジェクト ( また はそれのリファレンス ) を返すと定義されて いる叩 erator 十 ( ) オーバロード関数を , 適 用しているものとします。コンパイラはこ の式を , 左から右へ , ( A 十 B ) 十 C と評価し ていきます。しかしこれは operator 十 ( ) を 2 度コールすることになるのて、 , (A 十 B) の 結果を保持しておくためのテンボラリな値 を使わなければなりません。コンパイラが 生成するコールの形は , つぎのようなもの になるて、しよう。 f00 temporary = A. operator 十 ( B ) ・ f00 temporary2 = temporary. operator 十 ( C ) ; 上の、、 = クに関しては〔プログラムがコー ドとして書いた、、 = クて、はなく , 単にコンパ イラの内部的動作の説明用〕 , 叩 erat 。 r = ( ) は使われません。ここて、も , コピーコンス トラクタが使われるのて、す。上と等価なコ ードは , f00 temporary (). operator 十 ( B ) ) ; f00 temporary2 (temporary. 叩 erator 十 ( C ) ) ; この点が , 多くの C 十十プログラマを混乱 こて、念を押し させています。てすから , ておきましよう。叩 erator= ( ) は , すて、に 初期化済みのオプジェクトを , 別のオプジ ェクトへ代入するときにだけ , 使われるの て、す。上の場合のように , オプジェクトの 定義と初期化が同時に行なわれるときは , 必ずコンストラクタが使われます。そのと き , 新しいオプジェクトが , 同じ型のオプ ジェクトから〔それの値を元に〕初期化さ れるのならば , 使われるコンストラクタは コピーコンストラクタて、す。前出の、、 = 〃を 使って書いたコードは , 代入のように見え ても , 実は初期化〔新オプジェクトの生成 ( コンストラクト ) と , それと同時の値初期 化〕てあり , コンパイラはコピーコンスト ラクタを呼び出すのて、す。 式 A 十 B 十 C の結果を使用しないときて、も ( ここて、は副作用だけを目的に式を評価す る , と仮定しています ) , コンパイラは結果 を保持するためのテンボラリオプジェクト を作ります。上て、は結果は捨てられますが , D=A 十 B 十 C のような式なら , 結果は使わ れます。このときの、、 = 〃は明示的な代入文 て、すから , コンパイラは代入〔関数 operat or= ( ) 〕の返し値をどこかに収めるため に , 次のようなコードを生成するて、しよう。 f00 temporary3 = D. 0 rat0 作 (temporary2) ; 私がこういう細かい内部事情を知ったの は , ずいぶん前に Sun の上て、 AT & T の cfron tVer. 1.2 を使っていたときて、す。 cfront は C のコードを生成するのて、 , それはかなり醜 いコードて、すが , とにかく C 十十が内部て、何 をやっているのか , 知ることがて、きるのて、 す。 読者のみなさんは , コンパイラが何をや っているのか知りたければ , アセンプリ言 語のコードを出力させて , それを見ればよ いて、しよう。ただしこういう関数は , 多く のコンパイラが関数コールて、はなくインラ インコードとして生成しますから , なかな か分かりづらいて、しよう。 テンボラリな値が使われるケースは , 他 にもあります。それは関数コールのときに プログラマが明示的に定義する , テンボラ リオプジェクトて、す。たとえば , クラス f00 ーっの整数を引数として取るコンスト に ラクタがあるとします。そして関数 g ( ) は , f00 型のオプジェクトを引数として取りま す。そうすると , 次のような文て、は , テン ボラリな値が作られます g ( f00 ( 47 ) ) ; g ( ) のスコープの外にある名前の無いオプ ジェクトも , テンボラリな値て、あり , それ にはコンパイラが適当な名前を付けてコン ストラクタとデストラクタをコールします。 こういうテンボラリなオプジェクトも , 単純なオプジェクトの場合は間題ありませ ん。しかし複合型オプジェクトの場合は , 工イリアシングという問題が発生しますテ ンボラリオプジェクトの物理的表現が , そ れが作られた元のオプジェクトの物理的表 現と同じものになり , 元のオプジェクトは まだ生きているのに , 物理的表現だけが破 壊されます。そしてこういう場合にも , リフ ァレンスカウンティングが対策になります。 オプジェクトの代人 私が問題を指摘した最後の〔三つ目の〕 ケースは , オプジェクトの代入て、す。二つ の f00 オプジェクトを作って , 一方を他方へ 代入するとしましよう。 f00 X ( 11 ) , Y ( 47 ) ; X と Y はすて、に初期化済みて、すから , て、は確実に叩 erat 。 r = ( ) が呼び出されます ( コヒ。ーコンストラクタは , オプジェクトの 生成と初期化を同時に行なうときだけ使わ れます ) 。このとき , プログラマが独自の。 perator = ( ) を定義していないと , コンパイ ラが勝手にそれを作って , 単純な構造体の 代入を行ないます。 こて、もまた , 複合型オプジェクトては この場合に工イリアシングおよび , 物理的 表現の早期破壊という問題が起きます。 の問題を防ぐためには , プログラマが自分 て、 operator=( ) を定義して , コンパイラが 勝手に行なう代入処理を , やらせないよう にするのて、す ( 複合型オプジェクトに対して は , リファレンスカウンティングを利用し ます ) 。 しかし , 困ったものて、すね。コンパイラ はいったいどこまて , 楽屋裏てそういう勝 C + 十に実装するメモリ管理機能「リファレンスカウンティング」 17
特集。 Borland 3 』研究 List オプティマイズオプションなしのアセンプラ出力 for (i 0 ; i く 10 ; 十十 i) { xor dx, dx j 叩 short @1@114 @1@58 : arrCi] 〃毎回律義にアドレス計算 mov bx, dx shl bx, 1 / / int は 2 バイト lea ax, word ptr Cbp-20] 〃 arr [ 0 ] の実効アドレス add bx, ax 〃 arr [ i ] の実効アドレス mov word ptr [bx] , 0 〃 0 を代入 inc dx / / 十十 i @1@114 : cmp dx, 10 〃ループの終了 ? jl short @1@58 List BC 十十 3.0 のオプティマイズ 1 十 十 「 0 0 ・ 1 を 1 ・ ( 、 cd 0 0 0 0 0 (List 2 ) , -Ov(List 3 ) , -OI (List 4 ) , -O 2(List 5 ) の 4 個について見てみました。 まず , オプションなしの場合て、すが , 律 義に毎回アドレスを計算して , 0 を代入して います。なんとも素直て、すね。 次に , ー Ov の場合て、す。 -Ov というのは , ループ変数を適当にポインタに置き換え , かつ計算量を減らすというもの。普通は手 て、やるオプティマイズて、すが , 大量のルー プの場合には効果を発揮するて、しよう。ー OI は , ループを rep/stosw などの高速なアセン プラ命令に置き換えるものて、す。ー 02 は , も っとも高速なコードを出すためのオプショ ンて、す。ー OI て、見られた , 変数へのムダな値 のロードも削除されています。 これらオプションの違いが , 実行速度に どう影響するか , TabIe 4 にまとめてみまし ー 1 , 000 , 000 回のループを作り , f00 ( ) を ものて、す。が , コードが明らかに間違って 呼び出したものて、す。 いる場合もときどきありますから , 注意が この結果を見ると , かなりの高速化がな 必要て、す。日経 MIX の BorIand 会議て、も , い されていることがわかります。空の関数呼 あまりに急激に高度な最適化が導入されくつかバグが報告されています。 び出しを引き算して比を求めると , 2.3 倍の たせいか , コード生成においていくつかバ オプティマイズを指定して動作がどうも 高速化となります。 このように BC 十十 3.0 のオプティマイズ グが入ってしまったようて、す。オプティマおかしい場合には , オプティマイズを一度 イズが有効に働いたときのコードは良質な外してみるか , ー S て、アセンプラコードを吐 は , ッポにはまれば切れ味鋭く決まります。 List オプション一 02 List オプション一 OI( ループの圧縮 ) 5 4 List オプション一 Ov ( 誘導変数分析と計算量削減 ) 3 int i, arr[10]; for (i 0 ; i く 10 ; 十十 i) { xor dx, dx lea ax, word ptr [bp-20] 〃 arry [ 0 ] の実効アドレスー〉 ax / / なんで最初から s i に入れないのやら ? fflOV Sl,ax jmp short @1@170 @1@86 : arrCi] mov word ptr Csi], 0 add si,2 inc dX @1@170 : cmp dx, 10 jl short @1@86 〃 *S i に 0 を代入して , 〃 s i を 2 ( int 分 ) インクリメント / / 十十 i / / ループ終了 ? バグ int i, arrCIO]; for (i 0 ; i く 10 ; 十十 i) { mov cx, 10 〃ループカウンタ lea di,word ptr CbP-22] / / arr [ 0 ] の実効アドレス ds push / / セグメントをあわせて , POP e S / / ストアする値を AX に入れて , xor ax, ax / / それいけ ~ stosw rep mov word ptr [bP-2], 10 10 につじつまをあわせる arrCi] int i, arrC10]; for (i 0 ; i く 10 : 十十 i) { / / カウンタ用意 ~ mov cx, 10 lea di, word ptr Cbp-20] / / 実効アドレス準備よし push ds / / セグメントもあわせて , / / ストアする値は 0 だ xor ax, ax / / それいけ ~ StOSW rep arr[i] 10 はない / / 不要な i 特集 BorIand C 十十 Ver. 3.0 研究 33
実践アルゴリズム戦解法のテクニック 再帰降下型構文解析のプログラミングは BNF や EBNF て、記述された文法から自動的 てください 決して難しいものて、はありません。まず , にパーサのプログラムを生成するプログラ EBNF て、表現した導出規則の左辺をそれぞ ムはすて、に実用化されており , BNF から C 構文解析とは , ソースプログラムを導出 れ関数に割り当てます。電卓プログラムて、 ロ語によるパーサを生成する yacc や , EBN 規則に当てはめていく作業て、あるとみなす は , 「式」とか「項」 , 「因子」という非終端記 F から Modula-2 によるパーサを生成する Co Co などが有名て、す。これらをまとめて , 「コ ことがて、きます。当てはめた結果は二次元 号がこれにあたります。導出規則の右辺に 的な構造を持っていますから , 一種の木構 は非終端記号や終端記号が現れますが , ンパイラコンパイラ」とか「パーサシェ不レ 造て、表現することがて、き , プログラムを木 れらは下記のようにプログラミングします。 ータ」 , 「生成系」などと呼びます。 構造て、表現したものを解析木と呼びます。 非終端記号→対応する関数呼出しに置き換 さて , 手書きのパーサに戻ります。前記 一例として , ふたつの「似て非なる」式の解 の抽象的な説明だけて、はわかりにくいかも 終端記号→正しい記号が現れていること しれませんから , 疑似コードて書いた例を 析木を Fig. 3 と Fig. 4 に示しました。 再帰降下型構文解析の「下降」とは , 解析 を確認し , 次の記号を読み込 お見せしましよう。 木を根から始めてトップダウンに作成する List 4 は , Fig. 1 の EBNF のうち , 「式」以 む ソ〃や、、 { } 〃て、表現された「選択」や「繰り返 ところから名づけられたものて、す。また , 下の部分を疑似コードて、記述したものて、す。 し」は C 言語の while 文や switch 文を使って表 言語は通常再帰的な構造を持っています。 Fig. 5 の基本形を忠実に守って記述されてい この「電卓」の場合も , 「因子」を構成する非 現します。これらは Fig. 5 に示したひな形を ることがおわかりになると思います。と同 終端記号として「式」が現れていることから , 使って , それぞれ対応するプログラム断片 時に , 「こんな単純なものて、 , 本当に構文解 に置き換えていくだけて、記述て、きます。簡 析がて、きるのだろうか」と疑問に思われた方 間接的に再帰構造を取っていることがわか ります。この再帰構造を一群の再帰関数を 単て、すね。 もおありかもしれません。そう思われた方 使って認識する手法のことを「再帰降下型構 上記は見てのとおりの機械的作業て、すか は , Fig. 3 や Fig. 4 の式の例を使って , Lis ら , コンピュータによる自動化が可能て、す。 文解析」と呼びます。 t 4 をトレースされることをお勧めします。 いわば人間パーサということになりますね 電卓第 2 版の疑似コード List 4 の疑似コードを元に電卓プログラム の第 2 版を C 言語て、記述した例を List 5 に示 します。 構文解析 List 4 1 : 式 ( ) 3 : whi le (token 4 : get-token() ; 5 : 6 : 7 : 9 : 10 : 項 ( ) 12 : 13 : 14 : 15 : 16 : 18 : 19 : 因子 ( ) switch (token) 21 : case 左括弧 . 22 : get-token() ; 23 : 24 : if (token = = 右括弧 ) 25 : get—token ( ) ; 26 : else error ( ) ; 28 : 29 : break ; case 数値 30 : 数値の処理 31 : get—token ( ) ; 32 : 33 : break ; default : 34 : error() ; 35 : 36 : 37 : } = 加法演算子 ) { + ”を読みとばす * / いろいろな機能追加 この節て、は , 電卓プログラム第 2 版に機能 追加を施すことを考えてみましよう。まっ さきに考えなければならないことは , 単項 演算子十 , ーの追加て、す。 List 5 の電卓だ と , 「一 1 十 5 」のような式はエラーになって しまいます。これはちょっとお粗末てす。 単項演算子を追加するためには , 「式」の導 出規則を以下のように修正すればよいて、し , こて , 贒 ] 〃は初めて出てきたメタ記号 て、す。 [ ] は , が省略可能な項目てある ことを意味しています。また前述のように 、、十〃と単純化して書いてありますが , ヾ十ク 因子 ( ) ; while (token = 乗法演算子 ) { * " を読みとばす * / get—token() ; 因子 ( ) ; ク ッ 工 チ す / はす ば * るば ・ / と理いと * み処てみ 合読の来読 場を」がを の”式” 弧” 括 * 左 / * 数値の場合 * / / * 数値の処理をする * / / * 数値を読みとばす * / / * ” ( ”でも数値でもなければ、エラー * / 実践アルゴリズム戦略解法のテクニック 65
特集・ Bo 面 d い 3 』研究 り Windows プログラミングだけて、なく , 既 存の Windows アプリケーションのカスタマ イズまて、て、きてしまうのて、す。また , 統合 環境上にスピードバーがサポートされまし た。メニューの中のよく使用される機能を アイコンにまとめてあり , アイコンをクリ ックするだけて機能にアクセスて、きます。 BC 十十 3 . 1 と , BC 十十 &AFX3.1 には , 今まて、付属していた TC 十十 / Win の代わりに Borland C 十十 for Windows がノヾンドルさ れています。簡単にいうと , Windows 上の 統合環境て、最適化の機能が使えるようにな この最適化の機能自 ったのて、す。さらに 体も拡張されています。資料によると , 生 Fig. 29 TrueType のテモ 朝 0 れ S TrueType Demo 成されるコードのスヒ。ードが 5 % から 50 % 上 がっているそうて、す。 まず , 386 のコード生成というオプション が付け加えられています ( Fig. 30 ) 。これは 別にフラットな 32 ビットのメモリが使える ようになるわけて、はありませんが , 386 の レジスタを使用することて、コードを短く , ま たスヒ。ードを速くしているのて、す。 386 マシンしかターゲットにて、きなくなり ますが , Windows プログラミングだけて、は なく , MS-DOS プログラミングて、もある程 度オプティマイズに役立って、しよう。 また , オプジェクトデータ呼び出し規則 という , C 十十の This;tk インタを用いた新し いオプティマイズの機能もサポートされて います ( Fig. (1)0 C 十十て、プログラムを作 成する際に威力を発揮するて、しよう。 ツールとしては , Dr. Watson を機能拡張 したような WinSpector が新しく付属してい ます。 UAE ( 修復不可能なアプリケーション 工ラー ) を監視してログを採るツールて、す ( お化けのようなアイコンがかわいいて、す ) 。 Win32s, NT ' 92 年 7 月 7 日づけの Borland lnternational のニュースリリースがネットワークにアッ Fig. 31 386 のレジスタを使用するオプティマイズ 可 p ・夏、 bO ー我 sc ①ー fO 、、置 1 0 , s Bo a 賴 オプティマイズなし push bp mov bp, sp : init() for(i:O : i く 25 : i 十十 ) bx, dword ptr Cbp 十 6] les mov word ptr es : [bx] , 0 jmp shO は@1 @1 14 @1 @58 : @1 @58 Fig. 30 386 コード成生オプション @1 @58 ・ jmpshort @1 @114 mov wo 「 d ptr [bP-4] , 0 mov word ptr [bP-2] , 0 , fo 「 ( i : 0 : i く 500000 : i 十十 ) mov word ptr [bp-8] , 0 mov word ptr [bp-6] , 0 : long i , ド 0 , k , なし mov word ptr [bp-1 2 ] , dx mov wo 「 d ptr [bp- 1 0 ] , ax adc ax, word ptr [bp-6] add ax, word ptr [bp-8] mov dx, WO 「 d ptr [bp-4] mov ax, word ptr [bP-2] 386 使用時 , long i , ド 0 , k : mov dword ptr [bp-8] ,large 0 : for(i=O : i く 500000 : i 十十 ) [ mov dword ptr [bp-4] ,la 「 ge 0 jmpshort @1 @114 @1 @58 mov dword ptr [bp-12 ] , eax add eax, dwo 「 d ptr [bp-8] mov eax, dword ptr [bP-4] les m OV cwd les add adc les lnc bx, dword ptr [bp 十 6] ax, word ptr es : [bx] bx, dword ptr [bp 十 6] word ptr es : [bx 十 2], ax word ptr es : [bx 十 4] , dx bx, dword ptr [bp 十 6] , word ptr es : [bx] @1 @1 1 4 -po オプション使用時 lnc adc add cwd mov Jmp mov mov push word ptr [si] word ptr [si 十 4] , dx word ptr [si 十 2], ax ax, word ptr [si] short@1 @1 1 4 wo 「 d ptr [si] , 0 fo 「 ( i : 0 : i く 25 : i 十十 bp, sp bp cmp word ptr [si] , 25 @1 @1 1 4 : les cmp POP ret bx, dword ptr [bp 十 6] word ptr es : [bx] , 25 shopt @1 @58 bp shopt@l @58 bp PO P 「 et 特集 Borland C 十十 Ver. 3.0 研究 59