ROM 化 考察 TabIe 3 コンフィグレーションを記述するディレクテイプ クラス 内 CLASS O R D E R DUP ROM RESERVE 専有する。 p 「 intf ( ) 関数は大型オプジェクト だ。浮動小数点ライプラリはそれ自身て、 10 K バイト以上を消費する。不要なコードは取 り除くこと以外に解決策はない メモリ削減のために , LOCATE のインス トレーションには , 使用するライプラリに 応じて以下の選択をユーザに任せている。 1 ) DOS コール 2 ) 浮動小数点演算 3 ) コンソール I/O 物理セグメントをクラスへ割り付け クラス配置の順序指定 初期化データのコピーを作成 指定のクラスを ROM 上に配置指示 ( ファイルへ出力 ) 指定の領域へのコードまたはテータのはみ出しを検出し警告 ことがて、きる。もちろん MS ー DOS 全体を組 1 ) DOS コール などの代入文だけのプログラムを実行して み込めば , ほとんどの関数が使用可能にな DOS コールは INT21h の割り込みハンドラ も , デバッガを使わないかぎり , 動作確認 るが・・ 組み込みシステムて、は通常ひとつのアプ の形式て、サポートしている。デフォルトて、 がて、きない。このような場合には , シンク リケーションだけを実行する。したがって , ロスコープを用いて , 特定のポートにデー サポートしている DOS コールの数は少ない 特定のアプリケーションの実行に必要最低 が , ューザが容易に追加て、きる (TabIe 4 参 タを出力して動作確認をするとよい。ポー 限のメモリチップをポードに搭載する。メ 胆 ) ドによっては , ポートに LED がついている モリチップひとつの削減は , 量産ポードて、 ものがある。 この程度て、 Turbo C の malloc( ) 関数関係 は価格に響く。現在のパソコンて、は当たり まて、がサポートて、きる。 C プログラムの中核 pSFR->pmc0 前になった 640K バイトの RAM を搭載してい をなす関数のひとつだ。 pSFR->pm るケースは少ない もちろん intdos( ) 系の関数はすべて使用て、 ランタイムライプラリは大きなメモリを きる。 lSt DOS コールのインプリメントと拡張 0x00 ; 0x00 ; pSFR->p 0xff ; / * ポート 0 ( LED を〇 N ) * / pSFR-> p0 Oxoo; / * LED を OFF こんな簡単なプログラムて、動作確認がて、 きる。この動作確認がて、きれば , 後は比較 的楽だ 0LOCATE2f ッケージの解説に従っ もちろんポード自身の動 て進めるとよい 作確認がて、きていない場合には , C て、のデバ ッグから開始するのは愚だ。まずアセンプ ラて、 , 上記と同様のプログラムをチェック するのがまちがいない方法だろう。 ライプラリの ROM 化 MS-C,Turbo C には , 数多くのライプラ リが付属している。 ROM 化するからといっ てこのライプラリを全部あきらめる必要は くふうしだいて、数多くの関数を使う Int21Handler( / * スタックにセープした順番どおり * / 0 1 よっ 0 、 4 ・れ 0 ー 8 0 11 ワ 3 っ 0 4 ・戸 0 CD 行ー 8 0 11 っ 0 ・ 4 ・ 0 《 0 ー 8 、ーよ 11 11 1 よ 11 11 1 よ , 1 、ーよ 1 より朝ワ朝っ乙ワ 3 ワ〕っ乙り乙ワ 3 ワ 0 interrupt ds, dx, C X , bx, IP, C S , PSW WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD BYTE_PTR WORD_PTR int MCBP MCBP MCBP WORD / * General purpose counter / * General purpose BYTE pointer / * General purpose WORD pointer / * Temporary character storage / * Pointer to the current MCB / * Pointer to the next MCB / * A working pointer to an MCB / * Application segment identifier * / をー O O nma tmp mcb / * Clear the carry to indicate success * / enable() psw & ニ 0xfffe ・ 特集 ROM 化プログラミング考察 67
丿ズム 0 テータ構造入門 TabIe 3 探索時に調べるノヾケットの個数 ( 探索 1 回当たりの平均値 ) アレゴ 再八ッシュ時に順番にノヾケットを 調べる (List 3 の方法 ) 1 ーの 2 ( 探索が成功 ) 丁ータがみつかった場合 ァータがみつからない場合 ( 探索が失敗 ) まとめ 全バケット数 ー登録したデータ数 はハッシュ表の使用率 1 1 今回は , 探索アルゴリズムのうち , ハッ シュ法という技法を勉強しました。ハッシ ュ法には , 衝突が発生したときの対処法の 違いから , チェイン法とオープンアドレス 法の 2 種類があります。ハッシュ法を使う と , 探索 , 挿入 , 削除の操作を実質的に O ( 1 ) て行うことがてきます。 ハッシュ法の高速性は , 「ハッシュ表が十 分に大きい」ことを前提としています。も し , ハッシュ表の大きさ ( = バケットの個数 ) と登録するデータの個数のバランスが崩れ ると , 探索などの操作を一定時間て実行て きなくなります。 チェイン法ては , データの個数を , バケ ットの個数のせいぜい数倍程度にとどめる べきてしよう。オープンアドレス法ては , データの個数は , バケットの個数の 80 ~ 90 % 程度まてに抑える必要があります。 チェイン法ては , 探索の速度は遅くなる のに目をつぶれば , いくらてもデータを登 録することがてきます。しかし , オープン アドレス法ては , バケットの個数以上のデ ータを登録することは不可能てす。いずれ にしても , ハッシュ法ては , 「ハッシュ表の 2 ( 1 ーの 2 2 大きさが十分てある」ということが非常に大 切て、す。 次にメモリの使用量について考察しまし よう。チェイン法ては , あらかじめ割り当 るわけてす。その代わり , 連結リストのた 登録しなくても 1176 個分のメモリを消費す りません。極端な話 , データをひとっしか これだけのハッシュ表を確保しなければな 登録するデータの個数の大小にかかわらず , とすると , 1176 個のバケットが必要てす。 データを扱うためには , 最大使用率を 85 % 大きさ必要てす。たとえば , 最大 1000 個の また , 各バケットは , データを格納てきる ッシュ表を割り当てなければなりません。 あらかじめ最大のデータ個数を想定してハ これに対して , オープンアドレス法て、は , いうことになります。 いってみれば , 「基本料金十従量制料金」と ひとつがオーバヘッドとしてかかります。 ストを使うのて , データ 1 個当たりポインタ の大きさてすみます。その代わり , 連結リ ットは , ポインタをひとっ格納て、きるだけ 意しておけばよいてしよう。また , 各バケ あらかじめ 400 ~ 500 個程度のバケットを用 えば , 最大 1000 個のデータを扱うためには , ってセルをひとつずっ割り当てます。たと データを挿入するたびに , 関数 ma 日 oc ( ) を使 てておくのはハッシュ表だけてす。あとは , 再八ッシュ時にランダムな数列に よってバケットを調べる 1 loge 1 一 1 めのオーバヘッドはありません。つまり「完 全固定制料金」となっています。 ハッシュ法は非常にすぐれた探索アルゴ リズムてすが , ハッシュ表という ( 比較的 ) アルゴリズムとデータ構造入門 87 岩波書店 , 1989 年 [ 2 ] 石畑清「アルゴリズムとデータ構造」 , ム」 , 培風館 邦訳 : 大野義夫「データ構造とアルゴリズ gorithms", 1983 , Addison-Wesley. Ullman. ” Data Structures and AI [ 1 ] Ah0, A. V. , J. E. Hopcroft, J. D. 【参考文献】 する探索法を取り上げましよう。 リズムを使います。次回は , 木構造を利用 シュ法て、はなく , 木構造を利用したアルゴ ファイル内のデータを探索するにはハッ ようか ? ) 。 トのハッシュ表を使ったら何が起こるてし られます ( オープンアドレス法て , 数 M バイ テムて、はページングを多発することも考え ハッシュ表が大きくなると , 仮想記憶シス ハッシュ法は不向きだといえます。また , ら , ファイル内のデータを探索するには , スてきることを前提としています。てすか 大きなデータ構造を高速にくまなくアクセ
2 ) 浮動小数点演算 LOCATE'€ッケージて、 Turbo C の浮動小 数点演算を使用するには , ライプラリのソ ースファイルが必要だ。スタートアップコ ドて、 emuvars. asi をインクルードしてい Turbo C の浮動小数点演算のサポートに 必要なライプラリルーチンの初期化は簡単 て、 , 以下のコードて、行える。 push ; fa 「 call のシミュレート ds : [ emulst] ; 初期化 List セットべクタを記述した例 1 : / * The contents of the AH register is used to determine the service * / 2 : switch (highbyte(ax)) 3 : case DOS_SETVECTOR: (WORD_PTR) MK_FP(), lowbyte(ax) くく 2 ) WP d i sab I e ( ) 5 : 6 : = dx *wp 十十 7 : *wp ニ ds enable() 9 : break CS List DOS コール 4Ah のインプリメントの一部 call ret 以上の初期化てよいのだが , ひとっ問題 を残している。 Turb0 C のライプラリて、は 初期化ルーチンとエラー処理ルーチンて、特 定のポートに入出力を行っていることだ。 演算工ラーをチェックするために割り込み コントローラへの初期化を行っている。 のポート番号は PC ー 9801 版と IBM 版のライ プラリて、違いがある。使用しているポート をポードが使用していなければ問題は顕在 化しないが , そうて、なければソースコード を変更する必要がある。このモジュールは fpexcep. asm て、ある。 0 「 1 ・ 0 bO 〉・ 1 Q) , 1 0 CO 十 ) 0 & ー 0 《し 0 ー凵 ーし Cd 十し CO * X 00 一一 * Cd Cd 1 人っ 0 っ 0 4 ・戸 0 7 ー 8 0 11 ワ 3 CO 4 ・ L.O ^ し々ー 8 0 0 11 ワっ -4 ・ L-O 1 ↓ 1 よ 1 よ 11 1 よ 1 よ 11 ・ー 1 人 11 つなワ朝ワワワっ乙 / * Now either shrink or expand i t * / if ()x > ma->size) / * Expand is the next block is free/sufficiently large * / (MCBP) MK_FP()s + ma->size, 0 ) nma (MCBP) MK_FP()s + bx, 0 ) tmp ー if (nma->owner ! ニ 0 Ⅱ (ma->size 十 nma->size) く bX) / * Return the size block that can be allocated * / a X ma¯〉 size 十 ((nma¯>owner の ? nma—>size b x ー psw ー return : 3 ) コンソール I/O 多くのアプリケーションて、はコンソール I / O を使わずにすむ。一部のアプリケーショ ンてはコンソール I / O を使って p 「 in 呶 ) 関数 が必須の場合もある。どちらの場合て、も , p 「 intf( ) 関数が使用て、きることはプログラマ には福音てある。コンソールを使用するに は , DOS コールをとおしてコンソールへの 1 文字入出力を行う。接続する機器やポート ( シリアル / パラレル ) によって異なるのて、 , 最終入出力部分はユーザの責任てカスタマ イズする (Fig. 2 参照 ) 。 同様に DOS コールのリードをとおして , scanf( ) 関数 ,gets( ) 関数などの関数をサポ ートすることがて、きる。 68 CMAGAZINE 1990 11 TabIe 4 標準でサホートしている DOS コール ( Turbo C 例 ) 機能名 べクタのセット べクタの取得 DOS ノヾージョンの取得 ライト レ 0 CTL メモリ再割り付け ファンクション番号 0X25 Ox35 0X30 Ox3f 0X40 0X44 Ox4a
新登 0 十十 Version20 お待たせしました′ Version 20 新発売 そして、 AT&T C 十十日 el.2. O 準拠の完全日本語対応 C 十十、 MIWA C 十十 Ve 「 sion2.0 が発売となりました。 ・導出クラスか直接ーっ以上の基底クラスを持つような多重継承か可能。 ・非 C 十十コードとのリンクを明示的に宣言可能。 ・ ANSI C との互換性を向上させるためにキーワード volatileii 追加。 ・ static. const. および volatile なメンヾ関数を宣言可能。 ・純想関数を用いて、抽象クラスを宣言可能。 ・演算子 new と d ete を多義化して、クラスことに宣言可能。 ・テストラクタを明示的に呼び出せる。等々・ For More Advanced Serious Programmers C 十十は、 AT&T ベル研の BJa 「 ne St- 「 oust 「 up 博士により C の後継言語として設 計されたオプジェクト指向型の汎用プログラ ミング言語です。プログラミング言語として 広く普及している C の機能を全て継承しなが ら、更にクラス概念や仮想関数、多重継承な どの、数々の新機能を盛り込み、今や C に代 わる言語として全世界を席捲しつつあります。 MIWA C 十十は、 AT & T よりリリースされ ている AT & T Standa 「 d C 十十をベースに ミワシステムズコンサルティングが国産の PC 、 WS 向けにチューンアップを施した最新のプロ グラミング言語です。先進のオプジェクト指向 プログラミングのサポート、 C との互換性など の特徴はそのままに、さらに日本語処理関数に も対応しており、 90 年代のオプジェクト指向 型ソフトウェアの開発に欠かせない数多くの 新機能が拡張されていま魂 ・ MIWA C 十十の全製品が C 十十のソース・レ ベルで互換性あり。 ・コメント、リテラルに日本語の使用が可能。 ・日本語 FEP との共存が可能。 ・ MIWA C 十十に標準添付のライプラリの他 に、対応する C コンバイラの標準ライプラリ に含まれる関数も使用可能。 ・ MS ー DOS のシステム・コールをサポート。 (MS-DOS 版 ) ・ Mic 「 0S0 仗 C 準拠の日本語処理関数が使 用可能 0(NEWS 版 , 2 ロ 5 ロ G 版 ) MIWA C 十十のラインアップ SONY NEWS 対応版・ ・新発売 / Mic 「 osoft C V4.0 & V5.1 対応版・・発ノ中 SONY 日旧 C NEWS 対応版・ ・新発売 / TIJRBO C VI. 5 & V2.0 対応版・・・・・発ノし中 N E C EWS ー 4800 対応版・ 新発売 / 日立 HITAC E ー 7300 対応版・・・新発売 / 日立 2050G , 205 ロ / 32 対応版・発売中 ・・ ( 開発中 ) Panasonic BE 対応版 日立 205 ロ G , 2 ロ 50 / 32 ・・・・・ ( 開発予定 ) ・ IJNIX は AT & T 社の開発した OS て魂・ Mic 「 osoft. C. MS - ロ OS は、 Mic 「 osoft 社の製品で魂・ TIJ 日日 0 C は、 Borland 旧 te 「 nation 引社の製品で魂 ※ NEWS 版のユーサ登録がお済みでない方は、お早目にユーサ登録カードをこ返送願いま魂バージョン・アップのこ案内をお送りいたしま魂 ※ BBS を開局しました。ご質問、こ相談等お気軽にどうそ。 ( MIWA - NET. 045 ー 321 ー 675 ス 1200 / 2400b ロ s MNP5) MS—DOS 版統一価格 59800 円 IJNIX 版 売亠〔 CJNIX 版 〒 221 横浜市神奈川区台町 10 ー 15 株式会社ミワシステムスコンサルティンク Tel. ( 045 ) 312 ー 5418 ( 代表 ) ・ ( 045 ) 312 ー 2589 ( テック・サホート ) く資料請求番号 169 〉 0 0 0 0 0 0 0 0 0 0 0 0
P A R T S +C PARTS は、ソースファイルで提供していますので、必要に応じて機能変 更が可能です。 +C PARTS では、表示、印字等の処理を行う関数では、通常フォーマットフ ァイルを使用しています。フォーマットファイルを使用するメリットは、多少の変 更はアプリケーションプログラムの変更をしなくても、エデイター ( 市販のもの です。 ) で簡単に行うことができることです。 +C PARTS は、ライセンスフリーです。 C PARTS を使用して作成したアプリ ケーションプログラムに対しての、特別な契約をする必要がありません。 PARTS は、通常アプリケーション開発に必要と思われる画面制御、デー タ入力制御、帳票印刷制御、パーコード印刷制御い SAM 制御などの関数 をソースファイル形式で、しかも低価格で提供しています。 +C PARTS で提供する関数は、特殊な OS を使用する場合を除いて、基 本的には AN 引規格の関数を使用しておりますので、現在市販されている 一般的な C コンパイラーのほとんどで使用可能です。 (Lattice C, MS-C, QuIck C, TURBO C) O—PARTS—VOL. 本ソースライプラリーでは、フォーマットファイルを使用した帳票印字用の関数を提供していま 一般的に、帳票を作成する場合印字位置、印字桁数、タイトル文字、第線の印字など、一表の 帳票を作成する場合本体のプログラム、つまりテータの集計なとの処理よりも、前記の項目に ついての調整に多大な労力を費やすのか普通です。 そこで、本 C PARTS では、印字位置、印字桁数、タイトル ( 固定文字テータ ) 、第線の有無 については、あらかじめフォーマットファイルで作成しておき、プログラム本体の作業は単に順 番にテータを出力することのみとすることを可能としていま魂 また、フォーマットファイルは、専用工テイターを必要とせす一般的なエテイターで作成すること か出来るため、アプリケーションプログラム完成後でも、次の項目の変更か可能となっています。 1 ) 印字位置 2 ) 印字桁数 3 ) 罫線の有無及び罫線の種類 ( 太線、細線 ) 4 ) 固定印字文字の変更 また、アプリケーションプログラム中では次の項目の処理か可能となっていま魂 1 ) 日付文字列の印字 YY ・ MM DD 、 MM DD YY 、 YYYY 年 MM 月 DD 日、 YY 年 MM 月 DD 日の印字指定及び、 和歴変更が可能 2 ) 時間文字列の印字 、 hh 時 mm 分 ss 秒、 hh 時 mm 分の印字指定が可能。 hh : mm : ss 、 hh : m m 3 ) 数値データの編集 数値データに対して、 3 桁単位のカンマ付指定、通貨記号付加 ( 、 $ 、円 ) 4 ) 位置設定 データ印字時にフォーマットファイルの印字対象場所に対して、左詰め、右詰め、センタリング の指定ができます 5 ) 文字の大きさ データ印字時にフォーマットファイルの印字対象場所に対して、縦倍角、横倍角、縦横倍角、 指定ができます 6 ) 文字の強調 データ印字時にフォーマットファイルの印字対象場所に対して、強調印字指定ができます。 7 ) 網かけ データ印字時にフォーマットファイルの印字対象場所に対して、 3 種類の網掛け指定ができ ます。 8 ) アンダーライン付 データ印字時にフォーマットファイルの印字対象場所に対して、アンダーライン付印字ができ ます。 9 ) 上記 3 ) のカンマ付指定及び、 4 ) から 8 ) の機能を組み合わせて使用できます。 ( 実彳 ) ( フォーマット例 ) 下第のと・り第しまし 0 - P A 震 1 0 し . ー ・物い・・まして・ . よ・第・の第第に アイ第ル載ー興 ARTS•VOL. ソースラ 本ソースライプラリーでは、 PC9801 用プ丿ンター P 日 201 でバーコードを印字するための関数 を提供しま魂 バーコードの使用は POS 関連、配送関連など各種の流通業界だけでなく、最近ではロ M の 返信用はカに印字したり、招待状に印字することにより、応答の管理をしたり、自社製品にバ ーコードを付けることにより商品管理をしたりなど、いろいろな用途で使用されるようになって いま魂 本ライプラリーでは、フォーマットファイルを使用することにより、通常文字の印字位置、桁数、 バーコードの印字位置を随時変更可能とし、手軽にバーコードの印字を行えるようにしていま 使用可能なバーコードは次の通りです。 一般的な流通商品に付加されていて、通常は 13 桁のコードを使用しています。 1 ) 」 AN ただし短縮コードとして 8 桁も使用しています。 2 ) 主に配送個包のバーコードに使用します。 ITF 比較的初期に開発されたバーコードで、図書館の貸出しカード宅配便の配送用、 3 ) NW7 レンタルビデオなどで使用されています。 4 ) CODE39 1 ) ~ 3 ) のバーコードでは、使用できる文字が数字に限られますが、 CODE39 では 数字以外にもアルファベットが使用できます。 本ライプラリーでは上記バーコードの印字の際、必要な機能を全て提供していま魂 1 ) 印字バーコードの桁数の指定 2 ) チェックコードの付加 3 ) 印字可能文字のチェック 4 ) 印字バーコードの倍率設定 5 ) 付加数字の印字の有無
DOS ヨールを使用している ーイプラリは使用できない ROM 化のプログラムて、はパソコンとは違 う構成になっているため , DOS 上とは別の 環境て、走行する場合も少なくありません ( Fig. 3 ) 。このようなシステムて、は , たとえば List 8 : 7 : 6 : 5 : 3 : 2 : BSS セグメントに生成 int datal; func() static int data2; return( 0 ) : i nt / * datal / * data2 Fig. 6 ROM 化時のメモリマップ 00000000 00000004 00000008 RAM ROM putchar( 'A' ) ; を使用すると DOS コールの 1 文字出力の機能 が呼び出されて , DOS コールが呼び出され た段階て、暴走してしまいます。 C 言語て、はラ イプラリが簡単に使用て、きるため , 無意識 のうちになじみの関数を使用してしまう場 合も少なくないて、しよう。このため LSIC-86 のように stdrom. h というへッダファイルを : BSS セメント * / : BSS セメント * / ( シャドウ ROM ) 番地に射影される 先頭の 8 ノヾイトが 0 ~ 7 リセット時だけ ROM の 通常の CPU ボードでは BSS セグメント スタック領域 イニシャル PC イニシャル SSP DATA セグメント TEXT セグメント ROM 化 考察 用意して , ROM 化可能なライプラリを明確 にしているコンパイラもあります。 また , ライプラリに関しては DOS コール 以外にも初期値をもったデータの書き換え やプログラムコード自体の書き換えなどを 行っているかどうかにも注意する必要があ ります。最近のコンパイラはある程度 ROM 化を意識している部分がありますから , DOS コールを使用していない関数て、は通常 ROM 化が可能なコードとなっています。 DOS コールを使用している ライプラリを使用する方法 どうしても DOS コールを使用する関数を 使用したい場合は C コンパイラのライプラリ のソースリストを別途購入して , ソースリスト を修正するのが確実て、しよう。 もうひとつの方法は ROM 化システム上て、 DOS コールをエミュレートすることて、す。 MS-DOS て、あれば , DOS ファンクションの INT21h をエミュレートすればほとんどのラ イプラリが使用て、きるようになります。し かし , このエミュレートはかなり大変て、す から , 実際は使用したいライプラリが使用 しているファンクションに的を絞って , 少 しずっ使用て、きるライプラリを増やしてい くことになるて、しよう。 0 イ可能なライプラリ ROM 化可能なライプラリは処理系によっ て異なりますが , 一般的に以下のライプラ リは ROM 化可能なはずて、す。 Table 1 に示 した以外て、も , それに類するものは ROM 化 可能なはずて、す ( ただし , ROM 化にあたっ てはその処理系ごとに確認してください ) 。 特集 ROM 化プログラミング考察 41 ロ
応用 C 言語 C の道具箱 [ 機能 ] ( x , y ) を始点とするゾ en 行 x 刈 en 桁の大き さのウインドウとして pw を定義する。 textkei3( ) 関数 ( 付録ティスク収録 textkei 3. c 参照 ) ーー - 罫線の描画 [ 書式 ] #include <stdio. h> #include <stdlib. h> subwin. C 1 : #include く stdio. h> 2 : # i nc I ude く std I i b. h > 3 : # i nc I ude く memory. h> 4 : #include く dos. h> 5 : 6 : #include "pldwn. h" 7 : # i nc 1 ude ” w i ndow. h ” 8 : #include "cboxprot. h" 9 : 10 : MWINDOW *subwin(MWINDOW *pw, unsigned ylen, unsigned xlen, unsigned ystart, unsigned xstart) / * ラージメモリモードなので far 型 * / 14 : 17 : unsigned cpos ニ 0 18 : unsigned vramseg 19 : unsigned x, Y : 20 : unsigned seg, off; 21 : unsigned attrpos; 22 : unsigned x2; 23 : unsigned y2; 24 : unsigned char scrollwid; 25 : 26 : x2 ニ xstart 十 xlen ー 1 : ystart 十 ylen ー 1 : 28 : if(xstart く 0 Ⅱ x2 〉 = 80 Ⅱ ystart く 0 Ⅱ y2 〉 = 25 ) { 29 : 30 : return()U しい : 32 : 33 : 34 : 35 : 36 : 37 : 38 : 39 : 40 : 41 : 42 : 43 : 44 : 45 : 46 : 48 : 49 : 50 : 52 : 53 : 54 : } Li st 5 = 0Xa000 : #include "textkei2. h" textkei3(int xl, int x2, int y2, char att, int kind, int ura) X I en : ylen xstart : ystart : pw—>xlenn pw->ylenn pw->xl PW->YI pw—>curx pw—>cury pw->gattrib = DGATTRIB : pw->kattrib = DKATTRIB : pw->kkind = DKKIND pw->clearl = DC し EARL : pw—>leave ニ DLBAVE = DSCRO しし : pw->scroll if( (pw->psavecode wsaveinm(pw) ) ニ NU しい{ error ( " メモリが充分ではありません " ) : if( (pw->psaveattr wsaveinm(pw) ) ニ NULL){ error ( " メモリが充分ではありません " ) : return(pw) : [ 引数 ] xl, YI, x2, Y2 ←罫線を引くべき座標。 (xl, (l) から (x2, (2) まて罫線を描画。 att ←表示属性。具体的な指定について は , pldwn. h の定数を使用する。 kind ←描画の仕方を指定。指定の仕方は 以下のとおり。 ・四角の場合 角を直角に表示して 既存の線と交差した場合には十表示 1 既存の線と交差した場合には上書き 11 角を丸くして表示 ( 既存の線には上書き ) 12 ・横の直線の場合 単線 単線 ( 既存の線には上書き ) 二重線 二重線 ( 既存の線には上書き ) ura ←画面の指定。表画面に表示する場合 には 1 以外の整数を , 裏画面に表示する場合 には 1 を指定。 [ 戻り値 ] #include <stdlib. h> 正常終了の場合 0 を返す。 #include "window. h" [ 機能 ] #include "cboxprot. h" 画面上の座標 ( xl , (l) から (x2, (2) まて , att 属性をもっ罫線を kind の方式て描画す werase(MWlNDOW * pw ) werase( ) 関数 (List 6 werase. c 参照 ) ーーウインドウの消去 [ 書式 ] #include <stdio. h> 1 1 っ朝ワ】 [ 引数 ] * pw ←ウインドウ関連のパラメータを格 納する構造体のポインタ [ 戻り値 ] 109 応用 C 言語
ROM 化 考察 プログラミング を行う ) J M P END すなわち , スタックポインタを設定し , 必要なハードウェアの初期設定を行ったの ちに , C プログラムの関数 m 箚 n ( ) へジャンプ するわけて、す ( このとき , C70 ログラムへの 入り口の名前が main ( ) て、なければいけない という理由はとくにありません ) 。この場合 には , main ( ) に渡すパラメータはないのて、 , 通常の CP / M 下の main プログラムとは異な void main() lSt 1 maln 1 : # i nc 1 ud e く mac h i ne. h > 2 : 3 : #define CTRL 0X01 4 : #define DATA 0X00 5 : 6 : void init() outp(CTR し , 0X01 ) : 8 : outp(CTR し , 0X01 ) : 9 : outp(CTR し , 0X4 の : outp(CTRL, 0xCE) : outp (CTRL, 0X37 ) : 14 : 16 : char getch() while ((inp(CTR し ) & 0X02 ) 19 : return (inp(DATA) ) : 20 : 22 : 23 : 24 : void putch(char c) 25 : { while ((inp(CTRL) & 0X01 ) 26 : outp(DATA, c) 28 : と書かなくてはなりません。 さて , 上の初期設定プログラムの使い方 て、すが , ますこのプログラムを作り , アセ ンプルして , . sof ファイルにしておき , リン クするときに先頭につけます。 ポ—ト入出力 ポート入出力を行う場合は ,machine. h の 中て、定義されている inp ( ) 関数と outp ( ) 関数 ( 実はマクロ ) が使えます。 例として , 8251 ( lntel 社のシリアル I / O 用 LSI ) の初期設定 , 1 バイト入力 , 1 バイト出 力を行うプログラムを inp ( ) , outp ( ) を用い て書いてみましよう (List 1 ) 。 1 : #define dataport (*(char *)0xFF0 の 2 : #define ctrlport (*(char *)0xFFOI) 4 : init() VO i d 5 : 7 : ctrlport = 0X01 : 8 : ctrlport = ー 0X01 : ctrlport = 0X40 : ctrlport = 0xCE; ctrlport = 0X37 : 14 : 15 : Char 16 : { 17 : 20 : } 22 : 23 : VOid 24 : { 25 : 28 : } 絶対番地の参照 入出力ポートが I / O 空間て、なく , メモリ空 間に割り当てられている場合があります。 この場合の入出力操作は , I / 0 のときよりも ずっとスマートに記述て、きます。 たとえば , 先ほどのプログラムて , ポー ト 00h の代わりに 0FF00h , 01h の代わりに 0 FF01h を使って操作を行うと ,List 2 のよう に書くことがてきます。 getch ( ) while ((ctrlport & 0X02 ) return (dataport) : putch (char c) while ((ctrlport & 0X01 ) dataport 特集 ROM 化プログラミング考察 71
正常終了の場合は 0 を返す。 [ 機能 ] ウインドウ pw を画面から消去する ( 削除は しない ) 。 wrefresh ( ) 関数 (List 7 wrefresh. c 参照 ) ウインドウバッフアの内容を画面に表示 [ 書式 ] #include <stdio. h> #include <stdlib. h> #include <memory. h> #include <dos. h> werase . C 1 : #include く stdio. h> 2 : #include く stdlib. h> 3 : 4 : #include ” window. h ” 5 : #include "cboxprot. h ” / * ウインドウの消去 6 : 7 : werase (MWINDOW *pw ) 8 : Li st 6 wrestore(pw, pw->psavetmp) : free ( (void * ) pw->psavetmp) : return ( の : List 7 wrefresh . C 1 : #include く stdio. h 〉 2 : # i ncl ude く std I i b. h > 3 : # i nc I ude く memory. h> 4 : #include く dos. h 〉 5 : 6 : #include "pldwn. h" 7 : #include ” window. h" 8 : #include "cboxprot. h" 9 : 10 : wrefresh(MWINDOW *pw ) 13 : unsigned xl,yl; 14 : unsigned x2; 15 : unsigned y2; 16 : char attrib 17 : i nt k i nd 18 : int ura 20 : 22 : 23 : 24 : 25 : 26 : 28 : 29 : 30 : 32 : 33 : 34 : 35 : 36 : #include 'pldwn. h" #include 'window. h #include "cboxprot. h" wrefresh(MWlNDOW * pw ) [ 引数 ] *pw ←ウインドウ関連のパラメータを格 納する構造体のポインタ [ 戻り値 ] 正常終了の場合は 0 を返す。テンボラリバ ッフアの確保に失敗した場合には NULL を 返す。 [ 機能 ] pw て定義されたウインドウバッフアの内 容を画面に表示する。 wrsinupd( ) 関数 ( 付録ティスク収録 w 「 sinupd. c 参照 ) ・一一罫線枠を除いたウインドウバッフアの内容を画面に表示 [ 書式 ] #include <stdio. h> #include <stdlib. h> <memory. h> #include #include <dos. h> #include "window. h" xl pw->xl pw->yl x2 = xl 十 pw->xlenn ー 1 = yl 十 pw->ylenn ー 1 (char)pw->kattrib ・ attrib = = pw->kattrib kind ->psavetmp = wsavemem (PW) ) = NU しい{ i f ( ( pw error(" メモリが充分ではありません wrefresh-wsavemem 工ラー” ) : wsave (pw, pw->psavetmp) : wrs i nupd (pw) : textkei3(x1,y1,x2,Y2,attrib,kind,ura); return ( の : pw て定義されたウインドウバッフアの内 容の中て、罫線枠を除いた部分を画面に表示 する。 wrestore( ) 関数 ( 付録ディスク収録 wrestore. c 参照 ) テンボラリバッフアの内容を画面に表示 [ 書式 ] #include <stdio. h> #include く stdlib. h> #include <memory. h> wrsinupd(MWlNDOW *pw) [ 引数 ] * pw ←ウインドウ関連のパラメータを格 納する構造体のポインタ [ 戻り値 ] 正常終了の場合は 0 を返す。 [ 機能 ] 110 CMAGAZINE 1990 11
可変長構造体 学 本ロ 0 五ロ 乗松保智 C 言語には実行時に大きさが決定されるような可変長の構造 体を作る構文はありません。しかし , 配列を使ったトリック でこれをシミュレートすることかできます。今回はこの可変 長構造体について説明します。また , 便利な ( ? ) マクロ集を おまけにつけます。 Fig. 2 int array[O] ; 要素 0 個の配列 たとえば int 型のオプジェクト 10 個からな る配列を使いたいときには , int ar 「 ay [ 10 ] のように宣言します。にと当〃てはさま れた定数が確保される要素の数を指定して なぜこのような ANSI 規格外の例をもち出 は配列の先頭の要素を指しています。 います。このときにはメモリ上には Fig. 1 の してきたかというと , 実は 0 要素配列を使う ては要素の数を 0 にするとどうなるてしょ ように配列の領域が割り当てられます。そ ことがてきるとちょっとおもしろいことが の大きさは sizeof(int) * 10 ノヾイトて , array てきるのてす。実際 , 多くの処理系は要素 int array [ 0 ] Fig. 1 intarray[lo]; と書いた場合てす。 Fig. 1 の要素の部分を 0 数 0 の配列を許します。 個にしてみると , Fig. 2 のようになります。 array → 長構造体 要素 0 個の配列の大きさは sizeof(int) * 0 てす から 0 バイトてす。つまり a 「「 ay はメモリ上に はまったく場所をとらないオプジェクトと こて頭の体操てす。 【問題】可変長文字列をデータとしても なり , そのくせ array 自身は存在しないオプ ジェクトの先頭アドレスを指していること つ双方向リストを表現するためのデータ構 造を考えなさい。 になります。 可変長文字列を効率よく保存するために これはいったいどういう意味なのてしよ うか。結論からいうと , 意味はありません。 は , ma Ⅱ oc ( ) 関数を使ってヒープエリアにデ ータを溜めていくのがよいてしよう。 ANSI 規格は要素数 0 の配列は許していない また , 双方向リストてすから , 文字列デ のてす。すくなくとも , ひとつの要素が必 ータのほかにもリストを構成するためのポ 要だということになっています。 これ インタがふたっ必要てすね。これらを考え ては , ここて話が終わってしまいますから , とりあえず ANSI 規格は忘れましよう。 ると List 1 のような構造体になります。凵 ST C 言語雑学講座 117 a 「「 ay →ー -4 要素は存在しない一 a 「「 ay は存在しないオプジェクトを指している a 「 ray は先頭の要素を指している