ープロクラミング道場 Dr. 望洋の る ( ここて、は , それらを総称して「グラフィ IT を呼び出し , 初期化を行う。 グラフ BIOS を利用するには , 必ず GINIT ックルーチン」と呼ぶ ) 。これらを呼び出す グラフ LIO を利用するには , 必ずこの GIN ルーチンを呼び出さなければならない のて、ある。 IT ルーチンを呼び出さなければならない のとき , グラフ BIOS が使用する作業領域 このとき , グラフ LIO が使用する作業領域 (Fig. 3 ) のアドレスを DS に設定する。 PC ー 9801 シリーズの全機種で動作するグ (Fig. 2 ) のアドレスを DS に設定する。 ペイント関連命令用の作業用領域は , 同 ラフィックプログラムを作成するため ペイント関連命令用の作業用領域は , 同 ーセグメント内 (GINIT て、設定した (S) に存 にはノーマルモードではグラフ凵 0 , ーセグメント内 (GINIT て、設定した (S) に存 在しなければならない。したがって , C 言語 ハイレゾモードではグラフ引 OS を呼び 在しなければならないのて、 , C 言語から呼び から呼び出すときは , グラフ BIOS 作業領域 出せばよい 出すときは , グラフ LIO 作業領域とペイント とペイント用作業領域を合わせた領域を必 用作業領域を合わせた領域を必ず一度て、確 ず一度て、確保する必要がある。というのも , 保する必要がある。 2 回に分けて malloc などの呼び出しによる領 期ィ 域確保を行うと , 同一セグメント上に確保 というのも , 2 回に分けて malloc などの呼 グラフィックルーチンを利用するために されない可能性があるからだ ( スモールデー び出しによる領域確保を行うと , 同一セグ は , それなりの手続きを踏まなければなら タモデルの場合て、も far ヒープ上に領域確保 メント上に確保されない可能性があるから ない。一種の、、おまじない〃のようなものだ。 した場合は , 別のセグメントとなる可能性 だ ( スモールデータモデルの場合て、も , far ヒ ・ノーマルモード がある ) 。 ープ上に領域確保した場合は , 別のセグメ グラフ LIO の各コマンドは , 0xA0—0xC ントとなる可能性がある ) 。 ・拡張グラフィックモドの判別 ・八イレゾモード E のソフトウェア割り込みに対応している。 ハイレゾモードのグラフ BIOS は , すべて ハイレゾモードて、は , どの機種て、も中間 MS ー DOS を起動した時点て、 , それらの割り 0xID のソフトウェア割り込みによって呼び 込みべクタはセットされていないのて、 , グ 色の表示が可能て、ある。しかし , ノーマル 出すことがて、きる。 AH レジスタの値によっ ラフ LIO を使用する際は , ューザが , 割り込 モードはそうて、はない。ノーマルモードの てコマンドの指定を行う。ノーマルモード グラフィックモードは , みコードを割り込みべクタにセットする必 ・基本グラフィックモード のグラフ LIO と異なり , MS-DOS を起動し 要がある (CoIumn 1 参照 ) 。 Fig. 1 に示すよ うに , グラフ LIO の各機能の番地はアドレス た時点て、割り込みべクタは正しくセットさ ・拡張グラフィックモード れているのて、 , 新たに割り込みべクタを登 に大別される。 0XF9900 番地から格納されいる。 録する必要はない 基本グラフィックモードは , 割り込みべクタをセットしたあとに GIN Fig. 1 グラフ凵 0 コマンドエントリポイントテープル 工ントリ数 アドレス 十 0 十 1 十 2 十 3 機能 ( コマンド ) 0XF9900 Ox 1 1 十 0X04 GINIT OxAO 0X00 GSCREEN 十 0X08 OxA1 0X00 GVIEW 十 OxOC OxA2 0X00 GCOLORI 十 0X10 OxA3 0X00 GCOL02 十 0X14 OxA4 0X00 GCLS 十 0X18 OxA5 0X00 GPSET 十 Ox1C OxA6 0X00 G 凵 N E 十 0X20 OxA7 0X00 GC 旧 CLE 十 0X24 OxA8 0X00 十 0X28 GPAINTI OxA9 0X00 GPAlNT2 十 0X2 C OxAA 0X00 GGET 十 0X30 OxAB 0X00 十 0X34 OxAC 0X00 GPUTI 十 0X38 OxAD 0X00 GPUT2 GROLL 十 Ox3C OxAE 0X00 GPOlNT2 十 0X40 OxAF 0X00 GCOPY 十 0X44 OxCE 0X00 十 0X48 0X00 0X00 情報工ントリポイントのオフセットアドレス Fig. 2 グラフ凵 0 作業領域 オフセットアドレス 十 0X0000 十 0X1200 ラフ凵 0 作業領域 ペイント用作業領域 ( 任意の大きさ ) . Fig. 3 グラフ引 OS 作業領域 オフセットアドレス 0X0000 0X0100 0X0180 0X0380 ( 256 バイ 9 ヾラメータ作業領域 グラフ引 OS 作業領域 ( 128 バイト ) グラフ引 OS 作業領域 ( 2 ) 512 / ト ペイント用作業領域 ( 任意の大きさ ) Dr. 望洋のプログラミング道場 137
List 0 グー アクセス PC ー 9801 は Fig. 4-(a) に示したようにメイ ンメモリ上に 32K バイトの GVRAM (Graph ic Video RAM) を 4 枚持っています。 これら 4 枚の GVRAM はそれぞれが図に示 したように青 , 赤 , 緑 , 輝度を表していて , これらを重ねあわせて表示することて、 , 2 = 16 色の表示を行っています。 GVRAM 上て、 は 8 ヒ。クセル ( 8 ドット ) を 1 バイトとして管理 していて , 個々のビットの 0 / 1 て、ドットのあ るなしを管理しています。各バイト中て、は , それぞれ MSB ( bit7 ) がいちばん左寄りの , LSB ( bit0 ) がいちばん右寄りのドットを表し ています (Fig. 5 ー ( a ) 参照 ) 。 このように原色ごとに GVRAM を持つよ うな管理方式を「プレーン方式」と呼びます。 AT 互換機の VGA などもこの方式て、 GVRA M を管理しています。プレーン方式て、は , 個々の GVRAM を「プレーン」と呼びます。 このような構成の PC ー 9801 て、は , GVRA M にアクセスするのは比較的容易て、す。メ インメモリ上にすべての GVRAM が見えて いるのて、 , セグメントにさえ気をつけてや れば , 普通のメモリにアクセスするのと同 じようにアクセスて、きます。たとえば , C 言 語て、画面上 ( 0 , 0 ) の点に青て、点を打っプロ グラムは , List 3 のように記述て、きます。 L ist 3 て、 , 0X80 は 2 進数て、 10000000b となり , MSB すなわち左端の点がオンになった状態 てす。、ソ = を使っているのは , 元々 GV RAM 上にあったほかの点を消してしまわな いためて、す。 0Xa800 は青の GVRAM のある セグメントアドレスて、す。青以外のプレー ンには 0x7f すなわち 01111111b のように左端 のみを 0 としたマスクパターンをかけてやら なければなりません。さもないと , ほかの プレーンのドットと混ざって , 画面上に青 て、はない色が表示されてしまうからて、す。 このように GVRAM へのアクセス自体は 非常に容易て、すが , 点をひとっ打つだけて、 42 C MAGAZINE 1994 1 定 0 「し モ 0 ッ 0 フ ラ - ャレ十し 1 人ワワ 0 4 00 々ー 8 0 1 ↓ 90 っ 0 4 行ー 8 0 0 1 ムり 0 り 0 -4 行ー 8 0 レ 0 1 ワっ 0 4 ・れ 0 叮ー 8 、 4 4 -4 -4 ′・ -4 ・・ 4 ・ -4 ・ 4 ・リ t.n 「 0 10 にリ 00 れ 0 の 0 CD cD の 0 00 れ 0 0 りーーーーっーワーウーーヴーウー / * グラフィックモードの取得 * / 4 / * グラフィックモード設定 * / 0 0 0 0 14 0 0 0 0 0 れ 0 / * モード設定 * / = GR ー 640X400 ) { / * 640 x 400 の時は色数を選べる * / / * 色数設定 * / return ( r = 0X05 ) ? 0 画面上 ( 0 , 0 ) の点に青で点を打つ List 1 : unsigned char far *blue, *red, *green, *intense; 2 : blue = (unsigned char far *)MK-FP(0xa800, 0 ) : (unsigned char far *)MK-FP(0xb000, の : 3 : r ed (unsigned char far *)MK-FP(0xb800, の : 4 : g re en 5 : intense : (unsigned char far *)MK-FP(0xe000, の ; 6 : * い ue 0x 80 ; 7 : *red & = 0x7f; 8 : *green & = 0x7f; 9 : *intense & ニ 0x7f; GRCG を用いた点描関数 1 : / * GVRAM アドレス * / 2 : static unsigned char far *g-vram = (unsigned char far * ) 0Xa8000000 : 3 : 5 : * グラフィック点描画 for PC9801 ( px,py ) に色 color の点を打っ . 6 : 8 : VOid GraphicPset(int px, int PY, int COlor) unsigned int Ofst; unsigned char d-pset GrcgSet() : 13 : GrcgCOIor(coIor) : d-pset > > : ()x & 0X07 ) : 16 : g-vramC0fstJ ニ d-pset; = 0X80 : / * 座標からと ofst を得る * / 0
C 言語プログラミングレッスン・ も変わりません。よろしいて、しようか。 工ーション 構造体のいろいろな使用例を見ましよう。 例 : メンバを増やしてみる まず List 2 を見てください これは ,List 1 の構造体の簡単なバリエー ションて、す 0List 1 て、は国語・数学・英語の 3 教科しか扱っていませんて、したが , List 2 て、は国語・数学・英語・理科・社会の 5 教 科を扱うように変更してあります。 れてしまうのて、す。そのように変更したの 例 : 配列をメンバに入れる List 1 と List 2 て、はどこが違いますか ? が List 3 て、す。構造体のメンバの配列を参照 教科を表すメンバが増えています。新しい List 2 て、は 5 教科を表すときに , kokugo, する方法に注意しましよう。 メンバを追加すれば , あなたの目的にあっ , syakai というように個別の s. ten[0] suugaku, た「学生」を表す構造体を作ることがて、きる メンバを作りました。て、もここて、 , 先月の これは変数 s のメンバ ten [ ] の第 0 番目の要 ようになります。 配列を思い出してください。複数の教科の素を表しています。構造体のメンバを表す たとえば , このほかに「性別」を表すメン 点数を表すのに配列を用いました。 こて、のにヒ。リオド、、 . 〃を使い , 配列の 0 番目の要 バだとか , 「クラス名」を表すメンバだとか もそれを応用て、きます okokugo, suugaku 素を表すのに [ 0 ] を使っています。 List 3 を追加することもて、きるて、しよう (List 2 の , syakai という個別のメンバを作るの ( 動作結果は Fig. 6 ) は構造体のメンバに配列 動作結果は Fig. 5 ) 。 て、はなく , ten [ 5 ] という配列をメンバに入が含まれている例て、す (Fig. 7 ) 。 構造体の初期化 構造体の配列の初期化 Fig. 8 構造体の配列 C のプログラム あなたのイメージ 構造体 構造体 構造体 data [ 0 ] 0 0 0 0 struct student data [ 3 ] ; data[l ] 0 data [ 2 ] List List 0 十 ↓し、、 / 0 、ノ 0 ・ 1 0 O ・ 0 番ⅣんⅣんⅣんⅣんⅣん 0 席名語学語計っ ・ 1 ・ 1 + 》「—J 0 ・ 1 加出氏国数英合 On 0 + 》・ 1 O ・ 1 十》十》レ十》 ・ 1 O O ・ 1 ・ 1 十》 0 0 0 0 1 り介 0 4 0 6 ー 8 9 0 、 1 り 0 00 4 - -0 6 ー 8 9 0 1 人り介 0 -4 : -0 6 叮ー 8 9 01 よ 1 1 ・ 1 14 1 , よ 1 よ 1 1 、 1 りなり 00 りなりつ 0 0 みりりれ 0 れ 0 0 十 0 ・ 1 0 O \ 番影んⅣん影んⅣんⅣん 0 席名語学語計っ ・ 1 ・ 1 加出氏国数英合新 0 0 0 14 っ ・ , 1 、上、 1 ′、・く 0 ・ 1 ・ 1 O 十》 - ◆し十》し十》十し十レ OO ・ 1 O O ・ 1 ・ 1 0 0 0 0 ・よ 0 3 4 ′ 0 6 7 8 9 0 、 1 りな 00 4 一 -0 6 7 8 9 0 ・ 1 り 00 4 ′ 0 7 8 9 0 1 人 0 もっ 0 4 【 0 6 叮ー 8 、 1 、↓ 1 1 1 1 1 亠 1 1 1 ↓りつり 0 つり 0 0 り臨 0 り 00 00 っ 0 っ 0 00 っ 0 れ 0 れ 0 っ 0 数数数 号 / 点点点 番 * ののの 席名語学語 出氏国数英 数数数 号 / 点点点 番 * ののの 席名語学語 出氏国数英 = { 10 , "Yamada ” , 100 , 85 , 6 の : 0 0 8 6 8 行ー 一 0 【 0 8 8 9 6 0 0 り = 0 8 ー for (i = 0 ; i く 3 ; i + + ) { print—student(data[i]) ; C 言語入門講座 89
X 68 k 活 講座 List 1 3 List 1 3 ウインドウタイプを変更しながらウインドウを開いて閉じる / * 表示状態でオープン * / / * ウインドウのタイプを指定 * / (w-type くく 4 ) ー 0b0000 , / * 一番奥に表示 * / (vindov * ) 0 , / * クローズボタン描画しない * / 0 , / * ウインドウを指定 * / ( 1 くく 16 ) ー -task-id); / * WM0pen に成功したか ? * / if (result くの DEBUG PRINT ("Window Open Err!h"); exit て 1 ) ; 0 ′ー、十し↓し 0 CD ー 8 01 より 0 00 4 内 0 ー 8 0 び 0 14 り 0 00 4 ・ - 、リー 8 0 》 0 1 ーり 0 り 0 4 ・れ 0 内ー 8 0 ーーっ 0 っ 0 っ 0 00 4 - : , 4 ー 4 : ・ -4 ・・ -4 ・ -4 ・ LO 0 -. ^ リ - 、リリ 0 》′ 0 の 0 の 0 0 わ 00 れ 0 の 0 00 ーっー行ー《 1 : / * C-magazine SX サンプル ( その 4 ) * / 2 : 3 : / * ただウインドウを開いて閉じるだけ。 * / 4 : 5 : #include ” common. h ” 6 : 7 : / * いちいちスタックとヒープを指定するのが面倒だから * / 8 : asm ( ” . xdef _HEAP_SIZE 9 : _STACK-SIZE . xdef _HEAP_SIZE equ 0 STACK-SIZE equ 1024 1 5 : int vin-type[) WI_STD, WI_STD2, WI_PLN, WI_STDG, WI-STDG2, 24 : VO i d 25 : test-open(int w-type) int resul t : WM0pen ( / * カレントヒープゾーンヘレコードを作成 * / 0 , 29 : / * グローバル座標でウインドウ位置と大きさを指定 30 : GCC 拡張表記を用いる * / & ( rect ) { 0 + 160 , 0 + 160 , 319 + 160 , 200 + 160 } , / * ウインドウタイトル * / / * X68000 GCC 拡張表記 * / (LASCII * ) " \@C マガサンプル ( その 4 ) ' else / * 成功したら空ループしてウインドウをクローズ * / windov *win = -SXCALLPtr; i nt i , j : fo 「 (i = 0 : i く 32768 : i + + ) : 0 : j く 100 ; j + + ) WMDispose (win) : i 十十 ) もらった場合と自前て、ウインドウレコード 付録ディスクの リソスによる を用意した場合とて、呼び出すシステムコー ウインドウのオープ、 サンプルの説明 ルが異なります。 ウインドウを開く方法は , WMOpen を用 ウインドウクローズは以下のようになり 付録ディスクには 4 種類のウインドウサン いる方法以外にリソースを用いて開く方法 プルが収録されています ( TabIe 3 ) 。各プロ ます。 もあります 0SX-WINDOW て、は Mac ほどリ グラムは , 付録ディスク収録の、、 common. WMOpen で最初の引数が 0 ソースといった概念が発達していないのて、 h" をカレントディレクトリ , または環境変 WMDispose あまり用いられませんが , 自前て、ウインド 数、、 include" が示すパスにコヒ。ーした後 , WMOpen で最初の引数が 0 でない ウテンプレートと呼ばれるウインドウレコ gcc ー 0 -SX WSampIe?. c WMClose ードの雛形をリソースとして用意してウィ ( ? は 0 ~ 3 ) このふたつのシステムコールには , 両方 ンドウを開くことがて、きます。これについ て、コンパイルしてください。先月の XGCC が とも WMOpen が返した A0 の値 , ウインドウ ては , リソースの知識が必要なのて、機会を 正しくインストールされていれば , 正常に レコードへのポインタを渡します。 List 11 コンパイルて、きるはずて、す。 改めて解説したいと思います。 がウインドウレコードを自動変数 , つまり WSample0. c—WSample2. c て、はウイン スタック上に確保した場合のサンプルプロ ドウの開く位置を少しずっ変化させていま グラムて、す。 す ( いがいにこういった違いは目立たないも システムコール WMOpen は本当にウイン SX-WINDOW は , 連載第 1 回目て、説明し のて、す ) 。 ドウを開くだけて、 , ほかには何もしません。 今回収録したサンプルプログラムは , ウ たようにイベントドリプン方式のマルチタ たとえば List 9 て、 WMDispose を呼び出さな インドウを開いて閉じる機能しかありませ スクシステムて、す。今回のサンプルが , た いて、 , いきなりプログラムを終了させると だウインドウを開くだけて、何の操作もて、き ん。本来 , ウインドウを開く処理は , いろ 動かすことも消すこともて、きないウインド ないのは , 肝心のイベントの処理やウイン いろと準備をして「いよいよ人間との対話を ウが残ってリセットを余儀なくされます。 ドウの描画といった処理をまったく行って 開始」するときに初めて開くものて、 , 今回の List 10 てそれを行った場合にはスタック上 いないためて、す。次回は , イベント処理関 に確保されているウインドウレコードが解 ようにいきなりウインドウを開くようなこ 係を解説したいと思います。 放されてしまうのて、確実に暴走します。 とはしません。 146 C MAGAZINE 1 4 1 は 回 次
特集戻用ク目回を勁術 け取る状態になります。 こて、書き込みを うことがて、きないからて、す。 行うと , 書き込んだ値に対応する内部レジ CoIorSeIect レジスタは通常は 2 ビットて、 すから , デジタルバレットもアナログパレ スタが選択され , 値の受け取る状態になり ます。ここて、再び Attribute Data/Address ットも変更せずに 4 種類のパレットを切り換 デジタルノヾレットの設定は , AttributeD レジスタに書き込みを行うと , 値が内部レ えることがて、きます。 4 種類て、足りない場合 ジスタに書き込まれます。またこのとき At は Mode Control レジスタ ( 10h ) のパレット ata/Address レジスタ (3C0h) を用いて行い tribute Data/Address レジスタは再びレジ サイズビット (bit7) を 1 にセットすると , Co ます。このレジスタひとって、アトリビュー スタ番号を受け取る状態に戻り , 次のアク 10r SeIect レジスタは 4 ビット幅になり , 代 トコントローラの内部レジスタの選択と , わりに PaIette レジスタの出力が下位 4 ビット セスに備えます。 データの読み書きの両方が処理て、きます。 デジタルノヾレットレジスタへのアクセス に限定されます。この状態て、は , 16 種類の lnput Status # 1 レジスタ (3BAh or 3DA パレットを瞬時に切り換えることがて、きま は , Attribute Data/Address レジスタに P h) を読み込むと , Attribute Data/Address alette レジスタの番号 ( 00h ~ 0 伍 ) を設定する す。 レジスタが初期化され , レジスタ番号を受 Fig. 17 バレット バレットの設定ー Fig. 1 6 write Mode 0 デジタルノヾレット 012345 0 1 3 2 1 Plane 0 Rotate レジスタ CPU から 0 0 1 0 0 0 1 1 1 1 0 0 ↓ 0eh ( 1110b ) 110110 ↓ Enable Set/ 2 ピット Reset レジスタ 右へローテート ↓ ー↓日 ane ことに選択 —Plane 円 a 語 8e1 コ Function レジスタ ーーーー→論理演算← - ーーーー」論理演算指定 値論理演算 ↓↓↓↓ 00b S ET 01 b A N D 10b 0 日 1 1 b XO 日 Bit Mask レジスタ 0 0 1 1 1 1 0 A0000h , A0001 h , ・・ 黄 CoIo 「 SeIect レジスタ 0 0 Set/Reset レジスタ 0 1 1 1 0 0 1 1 0 1 1 0 DAC アナログノヾレット R G B 012345 012345 012345 ← ← 00h 01 h 02h 36h 1 1 1 1 1 1 1 1 1 1 1 1 000000 32bit 内部画像レジスタ OR アナログバレットを変更する List 1 2 ↓↓↓↓ VGA アナログパレットの設定 2 : = パレットの番号 ( 0 ~ 255 ) 3 : color_no 緑の輝度 ( 6bits ) 4 : green 赤の輝度 ( 6bits ) 5 : r ed 6 : 青の輝度 ( 6bits ) 国 ue = 7 : 8 : void GraphicPalette (int color_no, 9 : int green, int red, int blue) / * アナログパレット・レジスタの選択 * / 0UtP(0x3c8, color-no) : / * 値の設定 * / outp(0x3c9, red) : outp(0x3c9, green) ; outp(0x3c9,blue); 16 : ビットことに選択 結果 AO 0h , A 開 01 h. ・・・ 赤緑青 特集実用グラフィック術 53
てについて言及することはて、きないのて、 , 40 C MAGAZINE 1994 1 成の組み合わせがあり , これらを適切に設 PC ー 9801 には TabIe 2 ー (a) のような画面構 ません。 用可能かどうかをチェックしなければなり グ 16 色や GRCG , 640 x 480 の画面など ) が利 するために , 各種リソース ( たとえばアナロ また , 多様な PC ー 98 シリーズのハードに対処 種情報を保存しておかなければなりません。 要に応じて画面の状態を元に戻せるよう各 手続きをしながら , プログラム終了時に必 さらにグラフィック画面の表示開始などの す。解像度を決め , 表示可能な色数を決め , ん。実は , この作業が結構たいへんなのて、 するリソースを初期化しなくてはなりませ グラフィックを利用する際には必ず関連 グラフィック初期化 描画機能に関しては触れないことにします。 す。この点を考慮して , 本特集て、は GDC の ィック描画機能は優位性がなくなっていま CPU の高速化にともなって , GDC のグラフ 0nt0r0110r ) が搭載されていますが , 近年の 描画機能を持った GDC (Graphic Display C なお , PC ー 9801 シリーズにはグラフィック がら説明します。 に関して , サンプルプログラムをまじえな これから , これらふたつのハードウェア という 1 点て、す。 可能 ・ 640 x 480 アナログ 1677 万色中 256 色カ俵示 ての要件は , という 2 点て、す。また PC ー 9821 シリーズとし ている ・ GRCG ( グラフィックチャージャ ) を搭載し 能な画面を 2 画面持っている ・ 640X400 アナログ 4096 色中 16 色を表示可 本特集内て、の、、 VM 以降〃の要件は , めます。 アと PC ー 9821 シリーズとを対象にして話を進 一般的に、、 VM 以降〃といわれるハードウェ TabIe 5 グラフィック関連引 OS ワークエリア アドレス 0000 : 0495H 0000 : 0496H 0000 ℃ 499 H 0000 : 054DH 8 ピット 8 ビット 8 ビット サイズ 説明 更新するたびにここも更新すること。 0496H から順に青 , 赤 , 緑 , 輝度の順 GRCG のタイルノヾターンレジスタを設定する。 GRCG のタイルノヾターンを 利用する。 MSB が立っていなければ GRCG は利用可能 こをチェックし , GRCG がほかで利用されていないことを確認してから を更新しなくてはならない。なお GRCG を利用しようとするときには必ず GRCG のコマンドレジスタ設定値。 GRCG にアクセスした際には必ずこ で格納する MSB LS B 定する必要があります。ほとんどの設定は BIOS(int 18H ) を通して行えます (List 1 ) 。 初期化は BIOS のファンクション 42H と I / O GDC のドット修正モード 00 : REPLACE 01 : COMPLEMENT 1 0 : CLEAR 1 1 : SET GDC クロック 0 : 2.5MHz ( 200 ⅱ ne 時は必ず ) 1 : 5. OMHz ( 480 ⅱ ne 時は必ず ) 高速書き込みモード 0 : OFF 1 : ON GVRAMh\i ュアルポート RAM か ? 0 : NO 1 : YES DIP SW 2-8 の状態 ( GDC クロック ) 1 : 拡張 ( 256 色 ) 0 : 標準 ( 8 / 1 6 色 ) ( H98 では意味が異なる ) PC -9821 グラフィックモード 1 : YES 0 : NO EGC 利用可能 ? 1 : 0N(). OMHz) 0 : OFF(2.5MHz) PC ー 9821 て、は , 前記 PC ー 9801 にさらにいく Table 3—Table 5 に示します。 ポート 06AH を用います。それぞれの概要を Fig. 4 PC ー 98 シリーズ ( PC -9801 と PC -9821 ) のメモリマップ (a) PC ー 9801 シリーズ ( PC -9821 を含む ) FFFFFH E8000H E0000H C0000H B8000H B0000H A8000H A5000H A4000H A0000H 00000H BIOS ROM AREA GVRAM ( 輝度 ) ROM AREA GVRAM( 緑 ) GVRAM( 赤 ) GVRAM(B) CG ウインドウ テキスト VRAM RAM AREA PC -9801VM 以降のみ ( 一部機種は要 16 色ボー ド ) PC - 9801 ( 初代 ) , PC- 9801U2 以外はもう 1 セ ット GVRAM を持ってい て切り換えながらこれを 使用することかできる 一部機種 2 画面分のテキストとア トリヒュート (b) PC ー 9821 ( 256 色モード時 ) のメモリマップ FFFFFH 印 OS 日 OM AREA E8000H E0000H C0000H B8000H B0000H A8000H A5000H A4000H A0000H RAM AREA GVRAM WlNtX)W # 1 GVRAM WlNt:mV CG ウインドウ テキスト VRAM ( 640X819 ある ) BANK # 0 ~ # 1 5 GV 日 AM ( 512 灯ヾイト ) メモリマッブド I/O アトリビュート RAM AREA 1 画面分のテキストと 00000H
0 囚朝 C 言語プログラミング 結城浩 今回は構造体を学しましよう。構造 体はリュックサックのようなものです。 リュックには様々な種類の品物か収ま っています。構造体には , 様々な型の 変数かまとめられています。 く , 動くプログラムを書くことができたか ' ューコーナー を判断基準とするのもいいかもしれません。 いくら文法の細かいところを覚えたとして 先月のレッスンて、は「配列」について学び プログラミング言語を学ぶときのコツの も , 実際のプログラムが動かなかったら何 ひとつは , 初めからすべてを完璧に覚えよ の役にも立たないからて、す。 ました。配列というのは , うと思わないことて、す。初めから細かい ・変数に番号をつけたもの たとえば , for 文が理解て、きたかを調べる ーこだわりすぎるとイヤになってしまい ・複数の変数をひとつにまとめたもの のには , for 文を使ったプログラムを書ける ます。「ここは丸暗記しちゃおう」 , 「よくわ て、した。配列は変数の一種て、すから , かを調べるのて、す。どんな簡単な , どんな からないけど見切り発車しよう」 , ・定義 こは つまらないプログラムて、もいいけれど , ち オマジナイだと思おう」という工夫が必要て、 ・代入 ゃんと動くプログラムを作れるか。それを ・ : 参昭 ひとつの大きなステップと考えてください を思い出しましよう。 じゃ , どのくらい理解したら「 OK 」といえ これまて、学んだ多くの事項について , 自分 配列の定義 るのて、しようか ? そうて、すね・・・・・・とにか て、チェックしてみましよう。 学生のテータを構造体で表す List 1 List 0 ・ 1 0 O 攣・ ⅣんⅣんⅣんんⅣん 席名語学語計っ 加出氏国数英合新 + し + 》 - ・し十》 - 十し十》 0 ん 00 4 0 6 「ー 8 9 0 1-- 0 00 4 ′ 0 ^ 0 ー 8 9 0 1 0 っ 0 -4 りつっっ 0 りつな 0 りっ 0 っ 0 っ 0 っ 0 っ 0 介 0 00 っ 0 4 4 4 -4 4 taro. kokugo = 100 : taro. eigo ニ 60 ; taro. suugaku = 85 ; Jiro = taro,• jiro. id = 11 ; strcpy(&jiro. nameC0], " 次郎” ) ; Jiro. kokugo = 99 ; print_student(taro) : print_student(jiro) : 1 : #include く stdio. h> 2 : #include く string. h> 4 : struct student ( int id; char nameC20] ; int kokugo; int suugaku; int eigo; 10 : ) ; 12 : void main(void); 13 : void print—student(struct student s) : 14 : 15 : void main(void) struct student taro; 17 : struct student jiro; taro. id = 10 : 20 : strcpy(&taro. nameC0], ” Yamada") ; 21 : * 数数数 号 / 点点点 番 * ののの 席名語学語 出氏国数英 84 C MAGAZINE 1994 1
List 4 のように記述した場合 , rect 10Ca1 はスタック上に確保されて初期値は実行の 度にスタックにコビーされます。ただし , SX-WINDOW のシステムコールて、は , レク トアングルの値の操作自体を期待するシス テムコール以外て、は , レクトアングルの値 は操作されないし , たいていはある範囲を 指定するためだけに用いられるのて、、、値が 固定クて、ある場合がほとんどて、す。 こういった用途の場合には , GCC の拡張 記述方法が非常に有効て、す。 GCC て、は、、 { 〃 レクトアングルは , 「リードオンリ属性」の す。レクトアングルはポインタを介して渡 と、、 } 〃を使った初期化の記述方法にキャス メモリ領域に確保され , & 演算子て、そのアド すのて、 , 構築子記述て、初期化したレクトア トを組み合わせたヾ構築子記述クが可能て、 レスに変換されます。 List 6 が List 5 をコン ングルを , 内容を変化させるようなコール す 0List 5 の見かけの動作は , List 4 とまっ パイルした結果て、す。 に用いると予想て、きない結果をもたらしま たく同じて、す。 注意しなければいけないのは , この構文 す。また , GCC は同じ内容のものを発見す (rect) { 10 , 10 , 100 , 100 } と記述された て、作られた領域はリードオンリてある点て、 るとそれを共有するコードを生成するのて GCC の拡張表記を利用した LASC ⅱ文字列の記述 ウインドウを開いて閉じるだけのプログラム Fig. 2 レクトアングルの概念 ()e 升 0 , topO) 第、第一当すイ下冪 (rightO, bo れ 0m0 ) (rightl , bottom 1 ) List List 1 : / * C-magazine SX サンプル ( その l) * / 2 : 3 : / * ただウインドウを開いて閉じるだけ。 * / 4 : 5 : #include ” common. h ” 6 : 7 : / * いちいちスタックとヒープを指定するのが面倒だから * / 8 : asm( ” _HEAP_S IZE 9 : . xd ef . xdef -STACK-SI ZE -HEAP-SIZE equ 0 STACK-SI ZE equ 1024 15 : main() int result WM0pen ( / * カレントヒープゾーンヘレコードを作成 * / 0 , / * グローパル座標でウインドウ位置と大きさを指定 20 : GCC 拡張表記を用いる * / & ( rect ) { 0 + 100 , 0 + 100 , 319 + 100 , 200 + 100 } , / * ウインドウタイトル * / / * X68000 GCC 拡張表記 * / (LASCII * ) " \@C マガサンプル ( その l) ” 25 : ノ * 表示状態でオープン * / / * ウインドウのタイプを指定 * / ( 旧 STD くく 4 ) ー 0b0000 , / * ニ番手前に表示 * / 30 : (windov * ) / * クローズボタン描画 * / / * ウインドウ印を指定 * / ( 1 くく 16 ) ー -task-id); / * WM0pen に成功したか ? * / if (result くの DEBUG_PRINT ("Window 0pen Err!Yn"); ex i む ( 1 ) : 43 : 46 : 49 : 1 : #include く sxdef. h> 2 : 3 : f00 ( ) bar ()( し ASCII){ 15 , "C マガ SX-WINDOW"}); 5 : List 現在の common. h 1 : / * C-magazine 連載用へッダ * / 2 : 3 : # ifndef COMMON_H 4 : $define COMMON_H 5 : 6 : / * SX-Window システムヘッダ * / 7 : $include く sxdef. h> 8 : #include く sxlib. h> 9 : 10 : extern int _task_id; 11 : extern int —p—task—id; 13 : / * デバッグ用マクロ * / 14 : #define DEBUG-PRINT(MES) 17 : / * 便利のための文字列操作マクロ * / 18 : $ifndef strcpy 19 : #define strcpy(DEST, SRC) 20 : do { char *-d ニ (char * ) (DEST); char * s = (char * ) (SRC) ; while て *-d + + 23 : 24 : } while ( の 25 : #endif 27 : #ifndef strcat 28 : #define strcat(SR0. SRI) 29 : do { char *-d (char * ) ()R の : char *-s = (char *)(SRI); 30 : vhile (*-d + + ) while (*-d + + 35 : } while ( の 36 : #endif 38 : #endi f 39 : / * end 0 f f ⅱ e * / MES) DMError(1, e ー se / * 成功したら空ループしてウインドウをクローズ * / window *win _SXCALLPtr; f or ( i = 0 : i く 3 2768 : i + + ) WMDispose (win) : ニ *_S 十十 ) C MAGAZINE 1994 1 142
像レジスタに VRAM の状態を読み込んて、か 書き込まれます。 無視されます。よって , たとえば白または CPU が指定するアドレスのどのビットに ら書き込みを始めます。 灰色を探す場合は , CoIorDon' tCare レジ 書き込みを行うかは Bit Mask レジスタ ( 08 スタに 1000b をセットし , C010r Compare レ Write Mode 3 h) によって指定します。 ジスタに 07h または 0 をセットして読み出 Bit Mask レジスタの 8 ビットのうち 1 のビ 図形の描画や文字を書き込むときに使う しを行えばよいのて、す。 ットに書き込みが行われ , 0 のビットは 32 ビ と効果的て、す (Fig. 15 ) 。 3 Write Mode 1 ット内部画像レジスタの値が書き込まれま CPU は書き込みを行うビットパターンを VRAM 内て、画像データを移動するときに 指定します。 CPU からのデータと BitMas す。 便利なモードて、す (Fig. 13 ) 。 通常は書き込みを行う前に ReadMode 0 k レジスタ ( 08h ) との間て、論理積 (AND) を行 による読み込みを行って , 32 ビット内部画 い , 結果が 1 のビットに Set/Reset レジスタ VRAM からの読み出しを行うと ,VGA 内 部の画像レジスタに四つのプレーンの計 32 Read Mode 設定のサンプル ビットのデータが読み出されます。 WriteM ode 1 はその 32 ビットのデータを指定された アドレスに書き込むモードて、す。 CPU からのデータは使われす , アドレス だけが使われます。 VRAM からの読み出し と書き込みを交互に繰り返せば , 4 プレーン 全部のデータの転送が 1 プレーン分の操作て、 完了て、きます。 なお , 画像レジスタは各プレーンにつき 1 バイトて、すから , CPU が VRAM から読み 出しを行うときはバイト単位て、行わなけれ ばなりません。 Write Mode 2 特定のドットを書き込むときに使用しま す (Fig. 14 ) 。 CPU から出力されたデータは bit0 ~ 3 のみ が有効て、 , それぞれがプレーン 0 からプレー ン 3 に対応し , 色の指定を行います。たとえ ば CPU から 05h を出力した場合はマゼンタが Fig. 1 1 Read Mode 0 List * Read Mode を設定 2 : 3 : 4 : * Parameter: = Read Mode の指定 5 : r_mode 6 : 7 : void SetReadMode(unsigned char r-mode) 9 : register byte tmp; if (r-mode く 2 ) { * Read M0de は bit3 にある tmp = r-mode くく 3 : _asm { 16 : * Mode Register を選択 20 : dx, 0x03ce mov al, 0X05 mov 22 : dx, out 23 : * Read Mode を設定 25 : 26 : dx, 0x3cf mov a l, dx 28 : and al,0xf7 29 : al, tmp 30 : out dx, al 32 : 33 : } / * Graphic Address Register / * Mode Register を選択 / * Graphic Data Register / * M0de Register を読み込む Fig. 12 Read Mode 1 COIor Compa 「 e レジスタ れ 1 . 1 .1 .1 ・ 32bit 内部画像レジスタ 結果・一 Read Plane SeIect レジスタ れ新 1 .1 .1 . 新、一 結果ー ↓ (plane 2 のテータ ) CPU へ 比較ー↓ plane 2 ( 10b ) 灰 白黒青緑赤茶灰黄 A0000h , A0001 h , ・・ 白黒青緑赤茶灰黄 A0000h. A0001 h , ・・ ↓ CPU へ 50 C MAGAZINE 1994 1
C 言語プログラミングレッスン・ 問題 3 の解答 1 : #include く stdio. h> 2 : #include く math. h 〉 3 : 4 : / * 長方形を表す構造体 * / 5 : struct rectangle { double xl, yl; / * 左上の点 * / 6 : double x2, y2; / * 右下の点 * / 7 : 9 : 10 : void main(void); 11 : double distance(double a, double b) ・ 12 : double calc—area(struct rectangle r 14 : void main(void) struct rectangle rect; double area; rect. xl rect. yl 20 : rect. x2 rect. y2 22 : printf(" 長方形 (Xg,Xg))i(Xg,Xg) の面積は xg です。 23 : 24 : rect. xl, rect. yl, rect. x2, rect. y2, area) ; 25 : 28 : / * 29 : * 関数 distance() は差の絶対値を求める。 30 : 31 : double distance(double a, double b) 33 : return(a ー b) ; 34 : 35 : else { 36 : return(b ー a) : 38 : 39 : } 41 : * 関数 calc area() は、 * 与えられ長方形の面積を計算する。 42 : 43 : 44 : double calc area(struct rectangle r) double x, y; / * 二辺の長さ * / 46 : x = distance(). xl, r. x2); 48 : Y = distance(). YI, r. Y2); 49 : return(x * y) ; 50 : 51 : } List 1 2 Fig. 1 5 KBASE の結果 BASE. C のコンノヾイル ー入力ファイルの表示 A> LCC KBASE. C lld @link. i A> TYPE SAMPLE. DOC 1 結城浩 65 90 100 80 73 2 阿部和馬 8 2 73 63 21 44 3 伊藤光一 7 4 31 41 59 38 4 佐藤太郎 100 95 98 82 61 5 村松真治 55 48 79 90 88 6 進東三太郎 74 41 59 31 38 A> KBASE く SAMPLE. DOC KBASE. EXE の実行結果 ^ 0 物 0 6 り 0 《 0 り 6 0 6 《 0 《 0 、よ ^ 0 8 っーり朝 8 っー 1 ー 0 ん《 0 8 8 8 8 っー》 4- 4 点点点点点点点点点点点点 均均均均均均均均均均均均 8 ^ 0 00 0 00 ^ 0 8 0 《 0 00 00 0 8 4 っリれ 0 4 00 0 8 4- 4 0 んり 4 00 り編 4- 4- っ 0 00 0 り 0 点点点点点点点点点点点点 計計計計計計計計計計計計 0 0 っ 0 : 0 0 合合合合合合合合合合合合 00 っ 0 0 ー 行ー《 0 っー CD -- 0 れ 0 4 8 1 ー 8 8 、よっ 0 8 -4 8 8 点点点点点 7 4 っ 0 、 8 《 0 《 0 っー 8 4- ^ 0 っ 0 均均均均均 0 ・ー 0 ん 0 1 よ り 0 0 1 人 9 1 ム 平平平平平 8 りも -- 0 8 っ 0 8 8 0 》っ -0 っ 0 0 っ 0 、↓ 8 8 0 9 っ 0 1 よ 、 1 1 よ , よ 8 0 《 0 4 9 ー Ln 0 》 0 っー《 0 4- - ト 0 LO れ 0 識 - り 4 《 0 0 , よロ 0 8 14 : - ト 0 0 8 00 ・ 1 、 1 - - 点点点点点 0 》 7 っ 0 、 -4 -4 表 点低低低低低 -0 り 0 4- 0 -- 0 4 位 05 2 低最最最最最 : 6 8 ー 0 -- 0 ー 0 に 0 0 0 8 0 9 0 9 8 8 名馬一郎治太成郎治馬一太点 1 の浩和光太真三る太浩真和光三高点点点点点 順城部藤藤松東よ藤城松部藤東最高高高高高 均 号結阿伊佐村進に佐結村阿伊進・最最最最最 点 、↓ 0 臨 00 4 -- 0 れ 0 4- 1 -0 00 ^ 0 《 0 生席 計 均 、 1 り臨っ 0 4 -- 0 点 合 学人出 科科科科科計 1- り 0 っ 0 - LD 1 ・つ編っ 0 4- ′ 0 教教教教教合 Fig. 1 6 長方形の辺の長さ P(XI, YI) 2 縦の辺の長さ YI Y2 0 ( , Y2) X2 横の辺の長さ = は 1- x 引 て、すから , まず辺の長さを求めることを考 独て、 kokugo と出てきたら変数として定義し 起こしてしまったかもしれません。 KBAS えます。いま , 長方形は対角線上の 2 点て、表 E. C をいじってコンパイルし直し , 納得いく てある ( ありますね ? ) kokugo て、あり , 構造 現されています。辺の長さは Fig. 16 を見る まて、復習してください。 体の後のヒ。リオド、、 . 〃の次に kokugo と出て さて次回は「ファイル操作」と題して , フ とわかるように , 縦の長さは 2 点の y 座標の きたらメンバとしての kokugo て、す。 C コン 差 , 横の長さは 2 点の x 座標の差て、得られま ァイルを取り扱う方法について学ぶことに パイラは文脈から変数名かメンバ名か判断 す。関数 distance( ) は差の絶対値を求める しましよう。 してくれるのて、 , List 8 のように変数名とメ ものて、す。 2 点がどういう位置関係にあって これまても , ファイルをデータの入力や ンバ名に同じ名前を使っても C 言語の文法上 も大丈夫なように , 単に引き算をして差を 出力に用いてきましたが , それはすべて、、 < 〃 正しいプログラムとなります。 と、、 > 〃を使ったリダイレクトによるものて、 求めるのて、はなく差の絶対値を求めていま した。次回はプログラム中からファイルに データを書き込んだり , ファイルからデー たとえば List 12 のようになります。ちょ タを読み込んだりする方法を学びます。 っと難しかったて、すか ? 長方形の面積を れによって , 計算して得られた結果を半永 求めることは簡単て、すが , それをプログラ 久的に保存したり , 以前の結果を再利用し ムとして表現することは慣れないと厄介て、 今月は構造体について学びました。変数 , たりすることがてきるようになります。お 関数 , 配列 , for 文の知識を前提としてお話 すね。 長方形の面積 = 縦の長さ x 横の長さ したのて、 , もしかしたらだいぶ消化不良を 楽しみに。 94 C MAGAZINE 1994 1 問題 3 の解答 0