VO i d VO i d VO i d VOid VO i d VO i d VO i d lnteractor オプジェクトへの通信プロトコル List 5 = 0. の ; Draw(void) : Redraw (Coord I eft, Coord botton, Coord right, Coord top) : Read (Event&) ; HandIe(Event&) : Update(void) : Reshape (Shape&) : Resize(void) : Scene オプジェクトへの通信プロトコル List 6 I nsert (I nteractor*) : Remove (I nteractor*) : Raise(Interactor*) : Lower(Interactor*) : Move(Interactor*, Coord x, Change 0 nteractor*) : Propagate ( b001 ean) : List 7 VO i d VO i d VO i d VO i d VO i d VO i d VO i d VO i d VO i d VO i d Coord y, AI igment) : Graphic オプジェクトへの通信プロトコル TransIate(float dx, float (y) : ScaIe(float sx, float sy, float crtx = 0.0 , float ctry Rotate(fIoat angle, float ctrx = 0.0 , float ctry = 0. の : List 8 Clause オプジェクトへの通信プロトコル れた Text オプジェクトの表示領域の定義を行 うオプジェクトになります。さらに , Text に は , W 0 「 d , W h i t e S p a c e , C u s e , Sentance, paragraph, Display などの派生 クラスがあります。 Wo 「 d は文字列を表現す る Text オプジェクトになり , Clause や Sen- tence は , 複数のテキストオプジェクトの集 のメンバ関数やフレンド関数により定義さ オプジェクトへの操作や処理は , クラス ・オプジェクトの通信プロトコル す。 クトの集まりを扱うオプジェクトになりま なり , Picture は , 複数の G 「 aphics オプジェ ン曲線を表現する G 「 aphics オプジェクトに スがあり , Point や SpIine は , 点やスプライ EIlipse, Polygon, Picture などの派生クラ L i n e , C i 「 c , R e c t a n g , S P ⅱ n e , ラスて、す。さらに , G 「 aphic には , P0int, 表現されたイメージの修復を行うためのク り , Damage は , Graphics オプジェクトて の Graphics オプジェクトの基底クラスて、あ Graphic などがあります。 Graphic は , 多数 Damage, GraphicBlock, Persistent, 一方 , グラフィック関係のクラスには , ります。 まりを扱う (Composition) オプジェクトにな ました。つまり , ウインドウに文字が表示 されていても , その文字は , それを表示し ている widget が管理しているのて、あり , 文 字が自分自身を管理しているのて、はありま せんてした。ゆえに , 移動 , 拡大 , 縮小 , 再描画などの操作は , 表示している widget が個別にめんどうを見てやらなければなら なかったのてす。 InterViews< は , テキストやグラフィッ クをオプジェクトにすることて , 文字や曲 線に対する操作を , 文字などそれ自身に任 せています。したがって , 文字を表示する 場合ても , 個々の操作は文字自身に任せら れるため , それを表示している widget は , そういった厄介な処理まてめんどうを見な いてすみ , widget の作成はずいぶん楽にな ります。 テキスト関係のクラスには , Layout, StringEdit, TextBIock, TextViewer, Text void InsertAfter(Text* 01d , Text*) ; void InsertBefore(Text* OId, Text*) : void RepIace(Text* old, Text*) : などがあります 0Text は ,Text オプジェクト の基底クラスて、あり , Layout は , まとめら 旧 te Ⅳ iews のプログラム例 1 List 9 2 : 3 : 4 : 7 : 9 : 16 : 21 : 22 : 23 : static OptionDesc OS[] 20 : / / プログラム個有の追加オプションの情報の ( なし ) 記述。 { nil } -*-heIvetica-b01d-r-normal--34-*"}, {"*font" static PropertyData ps[] 15 : / / リソース情報の指定にこでは , フォントの種類を指定している ) 。 13 : / / うことができる。 * * 文字列を単に表示するだけのプログラム (gom i 1. cc) 5 : / / InterV i ews のヘッダファイルの読み込み / / I nterV i e ws ワールドの構築のための定義。 6 : #include く InterViews/defs. h 〉 8 : #include く InterViews/message. h> / / Message オプジェクトの定義。 〃 World オプジェクトの定義。 #include <InterViews/world. h> 1 1 : / / このプログラムは , 単に表示するだけのものである。この例では , メッセージ 12 : / / というオプジェクトを使ったが , 円とかスプライン曲線でもほぼ同じように扱 V 0 i d / / ただの ma i n 関数 0 C 十十プログラミング入門 93
C 十十 プログラミング 入門 というものがあります。クラス DLDeque は , 双方向リスト DLList を使っています。 ・ PQ クラス PQ は , 優先度っきキューを実装し ・ Deque クラス Deque は , 両方向待ち行列 (Double End Queue) を実装したものて , その内部デ ータ構造により , クラス XPDeque, DLDeque gstack. hp 1 : / / 汎用型スタックのプロトタイプの定義 2 : / / genc I ass スクリプトで処理し , インスタンス化を行う 4 : / / 例 ( 型 integer の要素について , インスタンス化をする ) 5 : / / genc lass% genclass integer val gstack [return] 7 : c I ass く T > gstack { / / く T > が型のテンプレート 8 : private: 9 : く T > * s : i nt p : i nt S i ze ; 12 : public: く T 〉 gstack(int sz = 100 ) { 13 : 14 : new く T>[size ニ sz]; S ーく T 〉 gstack(void) de 1 ete [s i ze] s : void push( く T> e) 20 : { cerr くく "stack overflow Yn" i f (p > = s i ze) 22 : e 1 S e 23 : 24 : 25 : 26 : 28 : } : セスする際には , そのインデックスが正当 な値かどうかが , 実行時に検査されます。 また , その範囲は伸縮可能てす。 クラス Plex の派生クラスは 4 つあります。 クラス F 曰 ex は制限された範囲内のみて、伸縮 可能て、あり , クラス XPLex には , その制限が ありません。クラス X 曰 ex に要素の論理的な 削除と回復をつけ加わえたのが , クラス M 曰 ex て、す。たとえば , p が曰 ex 配列とすると , p. del(3 ) とすることて、 , 次からの P [ 3 ] への アクセスは誤りになります。そして , p. undel(3 ) て、回復します。このクラス XPlex, M 曰 ex て、は , ハッシュ表などて、配列要素が疎 に存在し , その一部だけをしばしば参照す る場合の効率はあまり優れていません。も うひとつの派生クラス日 Plex は , 補助のイン デックス表によりこの問題を解決していま す。半面 , 通常のアクセスて、は一様のオー バヘッドがあります。 ・ Stack クラス Stack は , 先に汎用化の例を示した スタックをもう少し実用的に実装したもの て、す。そして , その実装のデータ構造によ り , 4 つのバーションのクラス VStack, FPStack, XPSatck, SLStack があります。 これらの働きは , だいたい同じて、すが , 内 部のデータ構造が異なります。ふつうの固 定長の配列を使ったものがクラス VStack て、 , F 曰 ex 配列あるいは X 曰 ex 配列を使った ものがクラス FPStack と XPSatck て、す。クラ ス SLStack は , 単方向リスト SLList を使って こて、の基底クラス Stack います。なお , は , データ型て、のインタフェイスおよび工 ラー処理のみて、 , 実際にインスタンスはも ちません ( 本連載第 4 回参照 ) 。 ・ Queue クラス Queue も , 先のクラス Stack 同様 に , キュー ( 待ち行列 ) を実装したものて、 , その内部データ構造により , 4 つのバーショ ンのクラス VQueue, FQueue, XQueue, SLQueue があります。内部データ構造に使 われているものは , クラス Stack と同じて、 す。 List 2 く T 〉 pop(void) { if (p く = の { cerr くく "stack underflow %n"; } { return s[--p] ・ e I S e lnterger. gstack. h 1 : / / 汎用型スタックのプロトタイプの定義 2 : / / genc lass スクリプトで処理しをインスタンス化を行う 4 : / / 例 ( 型 integer の要素について , インスタンス化をする ) 5 : / / genclass% genclass integer val gstack [return] 7 : class lntegergstack { / / lnteger が型のテンプレート 8 : private: 9 : lnteger* s; int p; i nt S i ze : 12 : p ub 1 i c : lntegergstack(int sz = 100 ) { 13 : new lnteger [size S -lntegergstack(void) { delete[size] s; void push(lnteger e) { 20 : if (p > ニ size) { cerr くく "stack overflow %n"; } 22 : e I S e 23 : lnteger POP (void) { 24 : if (p ←の { cerr くく "stack underflow Yn"; } 25 : { return s[--p] ; } e 1 se 28 : } : List 3 88 CMAGAZINE 19 7
愛 n 0 「 Error Ha れ引 ing D O S 〃 , p p . 13 0 ー 13 3 , M i c r 0 s 0 f t List 2 226 : 227 : 228 : 229 : 230 : 231 : 232 : 233 : 234 : 235 : 236 : 237 : mov push mov iret END TEXT ends CB-trap ax, endp word word ptr cs : Ca Ⅱ erAddr 工ラーコ ptr cs : ErrorCode , アプリケー ドを ax に ションに戻る ライプラリはエラーを正しく扱うのて、 , C 「 itica 旧「「 0 「は必要ありません。このシステ ムを , ほかのコンパイラを使用するプログ ラムの中て、使用するときは , そのコンパイ ラのライプラリを最初に調べてください MASM て、 ce. asm(List2) をアセンプルする には MASM / ML CE, また Turbo C て、 demo. c(ListI) をコンパイルしリンクするに は TCC DEMO CE. OBJ とします。 このシステムを使うと , 致命的工ラーを List 3 インタフェイス関数の使用例 / * 元の関数を復帰 setCEasker( oldasker ) : / * ・・・プリンタをここで使用する / * 別のインタフェイス関数をインストールして・・・ * / setCEasker( printer-asker ) : / * 現在のインタフェイス関数をセープ * / oldasker getCEasker() : askerfcnptr oldasker; 自作ユーサインタフェイスのプロトタイプ int far asker(int axreg, ind direg, int bpreg, List 4 アプリケーションにとって透明化すること がて、きます。これによってメンテナンスが 容易になり , 可搬性と信頼性を高めます。 [ 参考文献 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] Ray Duncan, Press, 1986 、、 Advanced MS ー List 5 28 : 26 : 25 : 24 : 23 : 22 : 20 : 19 : 17 : 16 : 15 : 14 : 13 : 12 : 11 : 9 : 6 : 4 : 2 : ce. h 1 : / * ce. h 一致命的工ラーと a sker 関数のデータ型 * / 3 : #define CE_INTERRUPT 0X24 5 : void interrupt CE_trap(void) ; 7 : typedef int (far *askerfcnptr) (int, 8 : void far setCEasker(askerfcnptr) : askerfcnptr far getCEasker (void) : int sireg); int) : / * 以下はエラーコードの意味 ... * / l=write * / int, int, WiIIiam James Hunt, 、、 The C T001b0X 〃 , pp. 370 ー 377 Addison ー WesIey , 1985 、、 DOS 2 . 0 Technical Reference ′′ pp. D-4 ー D ー 8 , IBM , 1983 Peter Norton, 、、 Programmer s Guide to the IBM ー PC" ,pp. 157 ー 160 Microsoft Press, 1985 Dan RoIlins , 'DOS Exception Han 、、 P C T e c h J 0 u r n a 1 d I i n g , Apr. 1987 , pp. 130 ー 140 typedef un ion { uns igned short ax : struct { unsigned drive : 8 : unsigned r_W : 1 : unsigned area unsigned actions unsigned unsigned typ } parts : 21 : } AXBITS; typedef union { O=read : / * 0=disk error; l=non-disk / * O=DOS sys; I=FAT; 2=dir; 3=data * / Danny Lawrence 氏はもとテネシー州の Kingsport Times-News 社のプログラマ て、 , 現在は MIDI アプリケーションのソフト ウェアを開発しています。 uns igned short di : struct { } parts; unsigned char di-hi : uns igned char errorcode : 28 29 : } DIBITS; C M AGAZIN 1990 7
Fig. 2 Zortech C 十十より優れている点 ・ AT&TC 十十 2.0 互換のストリームクラスのサポート ・メンバ関数へのポインタのサポート ・ C 十十の void* を Turbo C 十十では C 十十仕様の void * として扱うが , ・インラインアセンプラ ( 環境版からも使用可能 ) のサポート ・オーバレイのサポート ・に EE の浮動小数点演算のエミュレーションのサポート Zortech C 十十では ANSI C 仕様の void * として扱う C 十十のコードを C のコードに変換する cfront というトランスレータて、ある。トランスレ ータの利点は , C コードを生成するのて、 , コ ードジェネレータの必要がない点て、ある ( 実 行コードの生成には , 既存の C コンパイラを 使う ) 。そのため , C 十十処理系すなわち cfront 自身の移植作業は容易て、あり , 実際 , 多数 の UNIX, MS-DOS 環境などて、動作してい しかし , トランスレータは , 実際のプロ グラミングては , いくつかの問題がある。 最大の問題は , トランスレータが変数名な どのシンポルをいじるために生じる ( たとえ ば ,ba 「は ,aut0 ba 「などに変史されるだろ う ) 。それゆえ , デバッグ時には C 十十コー ドと実行コードの関係があやふやになりや すい。「デバッグのしやすさ」という点て、は , トランスレータて、はないコンパイラの出現 が待たれていた。 Turbo C 十十は , 直接実行コードを生成 する真 ( native ) のコンパイラて、ある。 MS- DOS 環境て、は , すてに Zortech 社が 2.0 のコ ンパイラ Zortech C 十十を販売している ( 両 ・ 10 ノヾイト long doub 厄のサポート ・強力なプログラマーズプラットホーム クラスライプラリ 者の簡単な比較は Fig. 2 を参照 ) 。 準的なクラスも決まっていない ( 数年後の 付属していないのが問題てある。また , 標 の処理系にはあまり多数の「既存」クラスが 既存のクラスを利用てきることだが , C 十十 オプジェクト指向言語の大きな利点は , Fig. 3 Turbo C 十十付属のクラスライプラリ ・リスト構造型 (list ) ・待ち行列型 (queue) ・スタック型 (stack) ・ヒープ型 (heap) ・配列型 ( a 「「 ay ) ・連想配列型 (dictionary) C 十十ては , 新たにストリーム入出力のた 見ない クラスて、定義した多種の型まて、めんどうを に代表される。しかし , fprintf は , C 十十の C のストリーム入出力機能は , 関数 fp 「 intf ストリーム入出力クラス スを紹介しよう。 る。次に , ストリーム入出力のためのクラ また , AT&T 互換のクラスも付属してい (polymorphism) を使うことがて、きる。 icity) と実行時に型を束縛する多様型 パイル時に要素型を決める汎化型 ( gener 用な型て、あるが , そのような型には , コン している。それらのクラスの大部分は , 汎 スは Fig. 3 にあげた ) , ソースコードも付属 ラスのライプラリが付属し ( 資料記載のクラ Turbo C 十十には , いくつかの独自のク ならないだろう ) 。 ANSI X3J16 委員会の決定を待たなくては めのクラス iost 「 eam を用意し , 多様な型の スマートな入出力を実現している。ストリ ームクラスのオプジェクト cout への出力は 以下の書式て、行われる。 cout くく” Turbo C 十十 is ”くく 2 ℃くく” \ n ” 書式て、は , 出力する式の型を検査し , 適 切な関数を呼び出すことて、処理される。 C 十十 は , 演算子の処理を関数として定義て、き , かっ , 複数の関数に同じ名前をつけること がて、きる ( 多重定義と呼ばれ , 引数の型と数 て , 適切な関数を決定し , 呼び出す機能 ) 。 つまり , 演算子に型ごとの処理を定義て、き る。したがって , int や利 oat の値て、も , 型を とくに指定しないて、も , 同じ書式て、出力て、 きる。 新たに型を定義したときも , たんに演算 子くくだけを用意すれば , 同じ書式て、出力て、 きる。これは , 新たな型を C 十十の既存の型 体系に組み込む際の重要な機能てある。 ストリームクラスは , C 十十 1.0 て、も ist 「 eam と ostream というふたつのクラスて、 提供されていた。それが , 2.0 て、は , iostream というひとつのクラスにまとめられた。し かし , Turbo C 十十て、は , C 十十 1.0 のスト リームクラスも用意されており , 過去のプ ログラムもコンパイル可能て、ある。 Tu 「 bO C 2.0 と Tu 「 bO C 十十の相違 Turbo C 十十は , Turbo C 2.0 と多少の 細かな違いがあり , Turbo C のプログラム て、も , そのままて、はエラーになる可能性が ある。以下におもな相違箇所をあげた。 ・可変引数をもつ関数プロトタイプは ANSI の仕様に従う。したがって , f00 ( int ba 「 ... ) と foo(int ba 「 ,int pi ,... ) を混合して使用て、 きない ・ ANSI と K & R の関数宣言を混合して使用 てきない。以下のように , ふたつの関数宣 言を混合して使うとエラーになる ① void fl(char i, int j); ② void fl(), j) char i;int j; 速報 Turbo C 十十最新レポート 19
ったく無茶苦茶なアドレスへとリターンし てしまうからてす。今回のドジは , このこ とと関係があります。 以前 , 「索引自動作成プログラム」という ものを作ったことがあります。 1 冊の本の 原稿を書き上げた ( または訳し終えた ) 後 , その索引を作る作業がけっこうたいへんだ から , パソコンを使って楽をしよう , と考 えたのてす。 こんなプログラムを構想しました。 1 原稿のテキストファイルを冒頭から読 んでいき , 索引に入れる語の候補語を 摘出する 2 メモリ中に蓄積されている「索引に採用 する語のリスト」と , その候補語を対照 の直前すなわち [bp—l] が最終成分 x [ 9 ] と させ , 語がリスト中に存在すれば , そ ーの土俵を して扱われていることがわかります。 の語があったべージ数 ( ノンプル ) だけ 、勇足すると ListI< は , 定義した配列の大きさを超え をメモリに登録する るアクセスを , x [ 10 ] および x [ 20 ] への代入 ListI と List2 て、おわかりのように , ローカ 3 メモリ中に蓄積されている「索引に採用 ル変数として定義した配列に対して , その 文として 2 度も試みていますが , C コンパイ しない語のリスト」と , その候補語を対 ラはエラーメッセージもワーニング ( 警告 配列の大きさを超えるヾ違反アクセスクを 照させ , 語がリスト中に存在すれば次 すると , それが代入文などてあれば , まず メッセージ ) も出さないのてす。この件につ へ進む 最初に , もとのスタックトップにあったリ いては , 後ほど触れます。 4 どちらのリストにも存在しなければ , ターンアドレスを書き換えてしまいます。 このように , ローカル変数領域が "sub その語を画面に表示して , 索引への採 ListI の例て、は , x[9] まてしかない配列に 〃という操作て、行われるのなら , 次 用の y/n をユーザに問う。イエスならそ 対して , x [ 10 ] にアクセスする , という違反 元を変数て、指定する配列 , すなわち可変次 の語と出現べージ番号を「索引に採用す 的代入によって , 正しいリターンアドレス 元配列は , 苦もなく実現て、きるはずて、す。 る語のリスト」に登録する。ノーならそ は破壊されます。 8086 の sub 命令て、可能なアドレシングモー の語を「索引に採用しない語のリスト」 ドは , ① reg, reg ② reg, mem ③ reg, imm こういうことをやると , プログラムはた に登録する ④ mem, reg ⑤ mem, imm の 5 通りてす。 reg いがい暴走します。なぜならば , 配列への 5 テスキトを読み進み , 次の候補語を探 は CPU のレジスタ , mem はメモリアドレ 違反アクセスによって書き換えられた , ま す ス , imm は即値 (immediate value) て、す。ロ ar 「 ay - test アセンプリ言語のソース出力 ーカル変数としての可変次元配列の実現に は , このうちの②が使えるて、しよう。すな わち "sub sp, Chensuu]" のような操作に なるてしよう。関数の帰値を次元に使いた いときは , ①のモードを使うことになるて しようね ( 68000 系の CPU て、は , 各命令にお いてもっと多様なアドレシングモードが可 能なのて、 , こういったことをいちいち確認 してみる必要はほとんどありません ) 。 しかし , 現在の C コンパイラは , スタック ポインタとして使われるレジスタに対して , 上記の③のモード ( 例 "sub sp , 10 つしか , ローカル変数の実現のために使っていない のてす。 配列テストプログラム ( a 「「 ay ー t. c ) List 1 : void array-test(void) char x [ 10 ] : 3 : 4 : x ① 5 : x [ 1 ] 6 : 7 : xC3) 8 : xC4] 9 : xC5] xC6] xC8] xC9] x [ 1 0 ] ニ x [ 20 ] = スス セセ クク 反反 違違 0 0 14 っ 0 SP, List ;void array_test (void) { イ 1 っ 0 っ 0 4 ・′ 0 《 0 7 ー 8 0 》 0 、 1 っ 0 っ 0 -4 ・戸 0 CD ー 8 0 ) 0 、 1 0 1 よワ 0 っ 4 ・戸 0 ^ 0 ー 8 0 1 よワ朝っ 0 -4 ・ LO ー 8 00 1 よっ 0 一 , 1 よっ 0 っ一 4 ・ LO CD 行ー 8 , , 0 1 」 1 よ 8 ー《 0 -- 0 -4- っっ 0 1 ・・ , 1 よ Q. a. a. 0. Q. a. a. a. a. a. ø. 十レ十し本し本し十》 + し + し + 》 + 》 + 》十レ↓し a. 0. a. 0. a. Q. a. a. a. a. Q. .- 0 a. 0 , + 》 - + し + 》 + し十レ - 十し + 》十レ十》十し十し本し near 0 0 , 1 よワ 0 : ロカル変数領域を無化 116 CMAGAZINE 19 7
0 「 tion ( Ma 「 5 示されなくなります。ただし , の場合は , p ⅱ ntf などを使った普通 の出力も使えなくなりますのて , cp 「 intf などの直接コンソールにア クセスする関数を使って , 表示を これまてに行われてきた Turbo Assembler & Debugger の取り扱いと同様に取り扱います。 Turbo Debugger & TooIs のスチ ューデントパックは 12 , 000 円 ( 税 別 ) , ラボパックは 1 セット ( ライセ ンス 10 組 , マニュアル 1 冊 ) て 80 , 000 円 ( 税別 ) になります。 0 Turbo Asærnber & 1.0 を登録してあるユーザは , Turbo Debugger & T001S 2 . 0 にアップデートてきますか ? アップデートてきます。 Turbo Assember & Debugger 1.0 やタ ーポプロフェッショナルの製品の ューザ登録してある方には , アッ プデートのご案内をお送りさせて いただいております。なお , アッ プデート料は 13 , 000 円 ( 税別 ) てす。 10 : { Q & A scanf て , 数値や文字を入力さ せていますが , 空入力 ( リターンの み ) しても scanf から抜けてくれな いようてす。 scanf< は , % c が指定された とき以外は , スペースも改行もす べて空白文字として読みとばされ ます。つまり改行を入力しても , scanf は無視するだけて , なにもし ません。 また , % d 指定などの数値を入力 しなければならないときに , 数値 8 : A 0 23 : } A 以外の文字が入力されると入力工 ラーになり , その文字は読み込ま れたことになりません。このとき は ,fflush(stdin) : などて入力バッ フアをクリアしないかぎり , 同じ 書式て読み込もうとしても正しく 読み込めないことになります。 なお , scanf の代わりに ,List1 の ような関数を使うと , 多少使い勝 手がよくなることがあります。 0 BGI を組み込もうとしても , メ モリ不足のエラーが発生して正し く組み込むことがてきません。 A BGI は , 通常 , ma Ⅱ oc を使っ て , ドライバを組み込むためのメ モリを確保します。統合環境内て BGI を使ったプログラムを実行する 場合は , 使用可能メモリがかなり 小さくなるため , 正しく動作しな ことがあります。 また , スモールデータモデルて は , near ヒープ領域が最大 64KB し かないため , メモリが不足するこ とがあります。このときは , graph getmem, graphf 「 eemem をユー ザプログラムて List2 のように再定 義し , far ヒープ領域を割り当てる ことて , 対応てきる場合がありま す。 c b 「 k 関数を使って , キーが押された場合の割り込みハ ンドラを設定しているのてすが , どうしても℃が表示されてしまい ます。 これを表示しないようにはてき 0 キーが押された場合 は , ℃が必ず標準出力に出力され ます。したがって , close(l) : な どとして , 標準出力のファイルハ ンドルをクローズすれば , ℃は表 行ってください ( List3 ) 。 List 1 1 : #include く stdio. h> 2 : 3 : int escanf(char *fmt, 5 : 6 : 7 : char buf[BUFSIZ] : gets (buf) : return vsscanf (buf, fmt, List 2 #include く graphics. h> 1 : #include く alloc. h> 2 : 3 : 4 : 6 : 8 : 9 : void far * far _graphgetmem(unsigned size) return farmalloc(size) : VOid far _graphfreemem ()O id far *ptr. unsigned size) farfree (ptr) : List 3 4 : 5 : 6 : 7 : 8 : 14 : 20 : 22 : 1 : #include く stdio. h 〉 2 : #include く dos. h 〉 3 : #include く io. h 〉 #include く con iO. h> i nt 00u nter = 0 : int brk-handler(void) counter 十十 : cprintf( ” STOP h it Xd tineXsYrYn" return counter く 3 ? 15 : nain() counter, counter 〉 1 ? ” S ” 1 ませんか ? ctrl brk (b rk_handl (r) : -close(l) : kbhit(): cprintf("Hit STOP 3 tines to break!Yryn") : lnformation from Compiler Makers 151
ラムとリンクをしようとすれば困ったこと になります。 C 十十 1.2 ては , キーワード overload を使 ったり , 関数群の最初の関数の名前は符合 化しないなどの姑息な方法を使っていまし たが , 複数のライプラリを使うときなどに 問題がありました。 C 十十 2.0 て、は , 名前を符合化しない関数 を , 以下のように明示的に指定てきるよう になりました ( 残りの関数は , すべて符合化 され , キーワード overload は不要になっ た ) 。 コンストラクタ コンストラクタ はないため , C や FORTRAN などのプログ 符合化された名前は , もはやもとの名前て、 f 0FPc という識別子が使われる ) 。しかし , とえば , f (int) は f 0Fi という , f(cha 「 * ) は 受けつけように符合化し , 渡しています ( た 義された関数名を , リンケージェデイタが 名前は受け付けません。 C 十十て、は , 多重定 デイタ (UNIX の ld など ) は , ュニークてない を生みだしますが , 大部分のリンケージェ の関数の多重定義機能は同じ名前の関数群 名前の問題がありました。というのは , C 十十 また , C 十十 1.2 ては , リンク時に若干の VO i d oops-tl (String s) String os; struct oops-t2 { / / 例外の型その 2 List 1 1 oops-tl (lnteger i) lnteger Oi : struct oops-tl { / / 例外の型その 1 例外処理の例 oops(String as, lnteger (i) { / / 例外が発生するかもしれない関数 / / まず例外かどうかを検査する if ()s = NU ししⅡ as = throw oops_t2(as) : i f (a s ー throw oops-tl (ai) : / / 本質的な処理 "gomi") { / / 例外だったら , 処理部に投げ飛ばす / / 例外だったら , 処理部に投げ飛ばす VO i d main(void) { String name : lnteger uri : / / 適当なサンプル try { / / このプロックで発生した例外は , 後続の catch が処理を行う / / 例外型 oops ー t2 の例外処理 catch (oops-t2 (2) { / / 例外の型が oops-t2 だったら . くく a i くく " が与えられた。こんなことちゃ困ります Yn" : cout くく " 関数 main から呼ばれた関数 oops で , 引数 ai に " / / 例外型 oops - tl の例外処理 catch(oops-tl (l) { / / 例外の型が oops-tl だったら .. oops(name, uri); / / 例外が発生しそうだなぁ . extern "C" int fprintf(const char*, また , プレース { } て囲み複数の関数 ( へ ッダファイルの # inc 旧 de 文てもよい ) を指定 してもかまいません。 ・ const メンバ関数 const メンバ関数は , C 十十 2.0 から用意 されたものて、す。 const メンバ関数というの は , インスタンスの情報を変更しないメン バ関数として宣言されます。たとえば , const F00 aFOO ; と宣言された aFoo に対し , 操作を許すメン バ関数を指示するわけて、す。クラス F00 の定 義が以ドのようだとすると , class F00 { private : public : lnteger get (void) const ; void insert(lnteger) ; メンノヾ関数 se 「 t は , ふつうのメンノヾ関数 てすから , aFOO . insert(0) : は , 工ラーになります。しかし , get は , const メンバ関数と宣言されていますから , lntegerg=aF00. get( ) ; というように , const のインスタンスに対 し , 操作を行うことがてきます。 ■ g 十十 g 十十は , FSF の gcc をもとに作成された 真の (native) コンパイラてあり , gcc 同様 , かなり優れた性能をもっています。 g 十十 は , かなり頻繁にバージョンアップされて おり , 最新の 1.36.2 は AT & T の C 十十 2.0 の仕様をほば満たしています。ただし , g 十十 は , AT & T の処理系をもとにせず , 独自の 実装を行っているため , 細部の動作が若干 異なるところがあります。しかし , 筆者が 気づいた動作の違いは , たとえ指摘したと ころて , 重箱の隅をつついているようなも のて , あまり気になりません。それよりは , 無料てソースコードが手に入る g 十十の魅力 C 十 + プログラミング入門 97
•const const を指定することにより , 読み出し専 用として限定することがて、きます。このタ イプのオプジェクトの値は , コンパイル時 に設定 ( 初期化 ) されており , その値を変更 するような操作が行われているかどうかが , 処理系によってチェックされます。 avolatile vo 1 ⅱ e は , 指定されたオプジェクトが , 予期せぬ場合 , 論理的に変更されているは ずがない場合においても , その値が変更さ れている可能性があることを表します。通 常 , vo ね t ⅱ e 指定されるオプジェクトは , ハ ードウェアによって変更されることが予想 されるもの , つまり , I/O にマップされてい るため不定期に更新されるメモリや , 割り 込み処理によって変更されるオプジェクト などて、す。 const と vo t ⅱ e のふたつを , ひとつの宣言 に指定することがて、きます。この場合 , そ のオプジェクトの値は , プログラムて、変更 することはて、きないが , つねに更新されて いる可能性があることを表します。 0 t0 「 s ( 宣言子 ) C コンパイラにおけるすべてのオプジェク トは , Fig. 8 に示す構文規則によって宣言さ れます。 ■ポインタ宣言 ポインタは以下の書式て宣言されます。 * 型変更子リスト ■配列宣言 配列は以下の書式て宣言されます。 識別子 [ 定数式 ] 多次元配列は , [ 定数式 ] のリストによっ て宣言され , 最初の ( もっとも左側の ) [ ] 内の定数式は省略可能てす。初期化を行う 34 CMAGAZINE 19 7 Fig. 3 Type-Specifiers type-specifiers. VOid char short i nt long float double singed unsigned struct-or-union-specifier enum-specifier typedef-name Fig. 4 テータタイプ VO id Char signed char unsigned Char short, signed short, short int, signed short int unsigned short, unsigned short int int, signed, signed int unsigned, unsigned int long, signed long, long int, signed long int unsigned long, unsigned long int float double long double struct-or-union-specifier enum-specifier typedef-name 場合には , すべての要素を指定しなければ パラメータリストによる新しいスタイル もひとつのパラメータ ( void ) が必要てす。 すが , パラメータリスト型ては , 少なくと 必要てない場合には省略することが可能て、 識別子リスト型て、は , 識別子がひとつも 識別子 ( 識別子リスト ) 2 ) 識別子リスト型 識別子 ( パラメータリスト ) 1) バラメータリスト型 関数は以下の 2 種の書式て、宣言されます。 ■関数宣 なりません。 ( ANSI スタイル ) の関数宣言は , 識別子リス トによる古いスタイル (K&R スタイル ) に比 関数プロトタイプによるチェック機能 を利用するなどの優位性があります。とく に古い処理系とのコンパチビリティを意識 する必要がない場合には , 新しいスタイル を使用するようにしたほうがよいて、しよう。 Type names ( 型名 ) 型名は , 識別子が省略された場合 , オプ ジェクトのタイプの宣言として扱われます (Fig. 9) 。
xCn + + ] data ; とします。また , スタックからデータを降 data ろす ( 削除する ) には , 76 CMAGAZINE 19 7 法の数式の値は , スタックを使って次のよ notation) とも呼ばれます。逆ポーランド記 逆ポーランド記法は後置記法 (post ー fix になります。 1 十 2 * 3 → 1 2 3 * 十 ( 1 十 2 ) * 3 → 1 2 十 3 * 1 十 2 → 1 2 十 たとえば , とは , 演算子を後ろに置く記法て、す。 ポーランド記法 (reverse polish notation) は , 逆ポーランド電卓になっています。逆 ンド電卓を実現してみました。関数 main くもなんともないのて , List2 ては逆ポーラ たんにスタックを作るだけてはおもしろ に応じて別の型に typedef します。 ては ELEM 型盟 ong になっていますが , 必要 ックに積む要素の型は , ELEM 型て、す。 List2 1 , 空てなければ 0 を返します。また , スタ どうかを返す関数てす。スタックが空なら ろします oempty は , スタックが空て、あるか は , スタックに要素を積み , pop は要素を降 スタックを初期化 , つまり空にします。 push empty) が定義されています。関数 init は , ための 4 つの関数 ( i n i t , p u s h , p 0 p , ましよう。 List2 には , スタックを操作する 具体的なスタックの実現例を List2 に示し 現されていることがわかります。 トては 0 (n) かかるのに比べて , 効率よく実 は挿入と削除が O ( 1 ) てすみ , 一般的なリス 必要があります ) 。このように , スタックて、 とします ( 実際には , あふれをチェックする 増加し , 要素を降ろすときにはひとつ減少 します 0PascaI のように配列の添え字が 1 か ら始まる言語ては , x [ n ] がスタックの項上 となります。 C ては , スタックポインタは次 に要素が積まれる箱を指しています。これ に対して , PascaI< は , 最後に積まれた要 素を指しています。 スタックにデータを積む ( 挿入する ) には , 23 : { 26 : } 30 : { 32 : } 53 : } 58 : { 60 : } うにして計算します。 ( 1 ) 数字ならそのままスタックに積む ( 2 ) 演算子なら , ふたつの数をスタック から降ろして演算を行い , その結果 を再びスタックに積む List2< は , 逆ポーランド記法の数式を入 力してキーを押すと答えを表示します。 配列による待ち行列の実現 スタックの場合には , 挿入と削除が同じ 端て、行われるのて、 , 要素の増減にあわせて スタックポインタを動かすだけて、 , 要素そ のものは移動しないて、すみます。しかし , 待ち行列の場合には , 挿入と削除が両端て、 配列で待ち行列を実現する (queue. c) List3 2 : 3 : 4 : 5 : 7 : 8 : 10 : 12 : 13 : 14 : 15 : 16 : 17 : 19 : 20 : 21 : 22 : 24 : 25 : 29 : 31 : 33 : 35 : 38 : 39 : 40 : 41 42 : 46 : 48 : 49 : 52 : 54 : 57 : 59 : queue. c 配列で待ち行列を実現する #include く stdlib. h> 6 : #include く stdio. h> #include く ctype. h> 9 : typedef ELEM i nt i nt / * 工ラ VO i d rea r : front : queue CQUEUE-SIZE] : 11 : #define QUEUE_SIZE 100 ELEM,• long 18 : #define next(a) (((a) + 1 ) % QUEUE_SIZE) / * 待ち行列の要素の型 * / / * 待ち行列の大きさ * / / * 待ち行列の定義 * / / * 待ち行列の先頭 * / / * 待ち行列の最後 * / ( 正確に言うと最後の次の要素を指す ) * / / * 次の要素の添え字を求める * / ーメッセージをプリントして ex i t する * / error (char *S) exit(l); fpr intf(stderr, s) : 28 : / * 待ち行列を初期化する * / init() VOid front = rear 34 : / * 待ち行列にデータを入れる * / enqueue(ELEM x) VOid if (next (rear) ニ front) error ( " 待ち行列がフルなので要素を入れられません \ n つ : que ue [rea r] rear ・ = next (rear) : 43 : / * 待ち行列からデータを取り出す * / 44 : ELEM dequeue ( ) ELEM if (front = = rear) err 。 r ( " 待ち行列が空なので要素を取り出せません \ n " ) : = queue [front] : X front = next (front) : return X : 55 : / * 待ち行列が空かどうかを調べる。 * / 56 : / * 空なら 1 、空でなければ 0 を返す * / i nt empty() return front rear :
最初の要素が削除の対象になります。スタ ーティングシステムては , 実行待ちのタス いきます。スタック ( の項上 ) ヘデータを挿 ク ( プロセス ) は待ち行列に入れられて , CPU ックては削除の対象となるのはもっとも新 入することを「積む」 (push down) , ( 項上か しく挿入された要素てしたが , 待ち行列て が空くのを待ちます。またディスクに対す ら ) データを削除することを「降ろす」 ( pop る入出力要求は , 待ち行列に入れられて順 は反対にいちばん古い要素が削除の対象に (p) といいます。 番に処理されます。 なります ( Fig. 4 ) 。待ち行列ては , 最初 , 最 スタックは , 非常に重要なデータ構造て , 後の代わりに先頭 (front), 末尾 (rear) とい 頻繁に使用されます。また , 私たちの日常生 配列によるリストの実現 う呼び方をします。 活ても , 無意識にスタックを使っているの 待ち行列のイメージを直感的に把握する をご存じてしようか ? あなたが英語の本 には , 私たちが日常生活て電話や自動販売 さて , 今度は , どのようなデータ構造を ( なんてもよいのてすが , ここては「 The Art 機などの前て行列を作っているところを想 使えばリストをうまく表現てきるかを考え of Computer ProgrammingJ ということに 像すればいいてしよう。新しく来た人は , てみましよう。もともと , リストは要素を します ) を読んているとしましよう。そし 行列の末尾 ( いちばん後ろ ) につきます。そ て , あるべージて意味のわからない単語に 線形に並べたものてす。線形とは , して , 先頭の人から順番に行列から抜けて 遭遇したのて , 英和辞典を開きます。その 順番に , という意味てす。そこて , 配列を いくわけてす。 使えばリストをうまく表現てきるのてはな とき , 来客があったとしましよう。さらに 待ち行列は , 文字どおりに , 窓口に並ん いか , と考えるのはごく自然なことてしよ 来客との応対中に電話がかかってきたとし て処理されるのを待つ , という用途に利用 ます。この時点て , あなたがまずなすべき フ。 します。たとえば , マルチタスクのオペレ もう少し具体的に考察してみましよう。 ことは , 電話に出ることてす。 ( 幸いにもキ ャッチホンに割り込まれずに / ) 電話の用件 Fig. 4 待ち行列 (queue) がすんだら , 来客の応対を再開します。そ 待ち行列から取り出す ( dequeue ) して最後に , 来客が帰ったら英和辞典て単 語を調べます。単語の意味がわかったら , 「 The Art of Computer Program mingj を再び読み進めることがてきます。 このようなケースては , やりかけの作業を スタックに積んておき , 後て取り出して再 開する , という手順を心の中て実行してい ることになります (Fig. 3 ) 。 プログラムの実行中にサカレーチン ( C 言 語ては関数 ) を呼び出すときに , 今の説明と まったく同じことが行われます。つまり , サプルーチンに実行を移す直前にプログラ ムカウンタの値をスタックに積み , サプル ーチンから戻るときにはスタックからデー タをひとつ降ろし , それをプログラムカウ ンタにセットします ( つまりその番地にジャ ンプするわけてす ) 。 待ち行列 待ち行列 (queue) は , 挿入が一方の端て のみ行われ , 削除が反対の端てのみ行われ るものてす。待ち行列ては , 最後の要素の 次の位置に新しい要素を挿入します。また , 74 CMAGAZINE 1 7 待ち行列に入れる ( enqueue ) 先頭 末尾 (front) (rea 「 ) 要素は一方の端 ( 末尾 ) から挿入され , 他方 ( 先頭 ) から削除される。待ち行列に挿入することを「列に入れる」 (en queue), 削除することを「列から取り出す」 ( dequeue ) という 逆ポーランド電卓 (stack. c) Li st 2 4 : 5 : #include く stdlib. h> 6 : #include く stdio. h 〉 7 : #include く ctype. h> 8 : 9 : typedef 地 ng E し EM, 11 : #define STACK_SI ZE 100 13 : E し EM stack CSTACK-SI ZE] : 14 : int 15 : 17 : / * 工ラーメッセージをプリントして ex i t する * / 18 : VOid error(char *s) 20 : fprintf(stderr, s) : exit(l); 22 : } 23 : 24 : / * スタックを初期化する * / 25 : VOid init() stack. c 配列でスタックを実現する / * スタックの要素の型 * / ″スタックの大きさり / * スタックの定義 * / / * スタックポインタ * /