src - みる会図書館


検索対象: 月刊 C MAGAZINE 1992年8月号
11件見つかりました。

1. 月刊 C MAGAZINE 1992年8月号

」丿う 別ラ入 プ成 7--0 イ乍 一フィ イ フ グ 特集 マスクを使って処理をするのが適切だと思 シフトが必要ない場合はそのまま左から byte maskR = 0xFF くく ()x & 0X07 ) ; いますが , 今回はいちおう C だけて、記述して と宣言します。 右へ描けます。右シフトもシフトしながら 保存されたビットマップへのポインタを 左から描けます。左シフトは反対から描い います。 これて、 , だいたいの場合は期待した動作 たほうが何かと都合がよいのて、右から描く src, リストアする VRAM へのポインタを d をするのて、すが , 先ほど保留した条件 , st, 横幅を xsize とします。矩形の処理は 1 ラ ことにします。 イト数が 1 バイトのときと , 保存したバイト 基本的には端を描いて , あふれた分と次 インの処理のループに還元て、きるのて、 , 1 ラ のバイトをシフトしたものを合成して描く 数と書き込みバイト数が一致しないときの インの処理に注目します。とりあえず , 保 存されたバイト数 (xsize) は 2 以上て、 ( つまり ことになります。それから , 反対側の端を 処理を加えてやらなければなりません。 1 バイト内に収まっていない ) , 書き込みバイ 描きます (List 41 ) 。反対側の端の描画時に バイト数不一致の場合 は , あふれたビットとの合成を考慮しなけ ト数が 1 バイトて、なく , 保存されたバイト数 と書き込みバイト数が同じとて、あるとしま ればなりません。 まず , 書き込みバイト数がレヾイトのとき あふれたビットを次のループに送るのに す。 を考えましよう (Fig. 10 ) 。左端と右端のバ ちょっと制限が多いて、すが , 例外的な事 テンボラリ変数を使っています (Fig. 9 ) 。ア センプラを使う場合は , ローテイト命令と イトが一致しているのて、 , 当然 mask を別に 項はあとまわしにしましよう。 書き込みバイトが 1 バイトのとき 制限っき描画 1 : / / 書込が lbyte 2 : byte msk = maskL & maskR; 3 : if (xsize = 1 ) ( / / lbyte で収まっている 4 : for (int py = sy; py ← ey; py + + ) ( 5 : if (diff > = の ( 6 : *dst = ((*src 〉 > diff) & mask) ー (*dst & mask); } else ( 8 : *dst : ((*src くく -diff) & mask) ー (*dGt & mask); 9 : 10 : 11 : Src 十十 ; dst + = 冊 RB 買 : 12 : 13 : 14 : } else { 〃 2byte にまたがっているが 15 : 〃書込サイズが lbyte なので左シフトにきまっている 16 : for (int = sy; PY ← : PY + + ) { 17 : cmp : ((*src くく -diff) & maskL) ー ((*(src•l) 〉 ) rdiff) & maskR): 18 : *dst : (cmp & mask) ー (*dst & -mask); 19 : src 十ニ 2 : 20 : dst + ニ HORBYTES; 21 : 1 : if (diff ニ / / シフトなし 2 : / / 左端を描く 3 : *dst = (*src & mskL) ー (*dst & zskL) : 4 : / / 間を描く 5 : fmemcpy()s い 1, src + 1, 6 : xsize-2); 7 : src 十 = 8 : dst 十ニ xsize—l; 〃右端を描く 9 : ー (*dst & maskR); *dst ニ (*src & maskR) 10 : 11 : } else if (diff > の { / / 右シフト 12 : / / 左端を描く 13 : *dst ニ ((*src 〉 > diff) & maskL) ー (*dst & maskL) ; 14 : *src くく rdiff; 15 : / / 間を描く for (int dx 17 : 2 ; dx ← xsize-l; dX+-) { 18 : 十十・ dst++ : *dst ニ cmp ー (*src > 〉 di (f) : 20 : / / あふれたビットを次に送る 21 : 22 : cmp = *src くく rdiff; 23 : / / 右端を描く 24 : ニ ((cmp ー (*src diff)) & maskR) (*dst & maskR) : 25 : *ds t 26 : } e I se if (d i ff くの { / / 左シフト 27 : / / 後ろからかきもどす 28 : diff ー -diff; 29 : 30 : src = XSize ー 1 ; dst + = xsize ー 1 ; 31 : / / 左端を描く 32 : ニ ((*src くく diff) & maskR) 33 : *ds t maskR) : 34 : cmp ニ *src > 〉 rdiff; / / 間を描く 35 : for (int dx ニ 2 ; dx ← xsize-l; 38 : dst- ー (*src くく diff) ー cmp; 39 : *ds t / / あふれたビットを次に送る 40 : 41 : cmp = *src > 〉 rdiff; 42 : 45 : 46 : 22 : 23 : } 修正した右シフトの場合 1 : if (dsize 〉 xsize) { 2 : 〃あふれた 3 : *dst = cmp ー (*dst & maskR) : 4 : } else { 5 : *dst = (cmp ー (*src 》 diff)) ー (*dst & maskR) : 6 : S rc 十十 : dst-- / / 右端を描く *dst ニ (*dst & -maskL) ー (((*src くく diff) ー c 叩 ) & rnaskL); 修正した左シフトの場合 1 : if (dsize く xsize) { cmp ニ (*src > > rdiff); 2 : 3 : src— *dst ニ ((*src くく diff) ー cmp) ー (*dst & maskR) : 4 : 5 : } else { *dst : (*src くく diff) ー (*dst & maskR); 6 : 8 : cmp ニ (*src 〉 > rdiff) : 特集 PC ー 98 田グラフィックライプラリ作成入門 51

2. 月刊 C MAGAZINE 1992年8月号

切り直さないといけません。 mask 自体は左 と右の mask のビットごとの and を取ったも のになります。 byte mask = maskL & maskR 書き込みが 1 バイトになる場合には , 保存 されたバイト数が 1 バイトて、済んて、いるとき と , 2 バイトにまたがっているときの 2 通り あります。さらにシフトの方向も考慮しな ければなりません。ところて、 , 書き込みバ イト数が 1 バイトて、保存バイト数が 2 バイト て、あるならば , 左シフトの場合しか原理的 にありえません。 1 プレーンのみの処理に注 目して , List 42 のようになります。 次は保存されたバイト数と書き込みバイ ト数が一致していないときて、す (Fig. 11 ) 。 つまり , 保存してあるイメージにシフト操 作を加えて書き込んて、いますが , 過不足な くイメージが保存されていた場合 , 右にシ フトすると保存してあるイメージの右端を 越えてはみだすビットがて、てきます。また , 左右に端数ビットがある場合 , 左シフトす Fig. 11 るとひとつ前のバイトに収まってしまうこ とがあります。当然 , 保存してあるイメー ジのバイト数て、処理が可能な場合もあるわ けて、す。 シフト数が 0 のときは当然何も必要がない のはあきらかだと思います。右シフトの場 合を考えてみます。左端は普通に書いてか まわないてしよう。それから間を描きます。 この長さは書き込みバイト数分書き込みま す。 問題は右端て、す。右シフトの場合は書き 込みバイト数が保存されたバイト数と同じ か 1 バイト多くなる場合が考えられます。バ イト数が同じ場合はすて、に書いたのて、 , 1 バ イト多い場合の動作を考えます。この場合 , 前のバイトから送られてきたものだけを , ただ画面と合成すればいいことはすぐわか ります。このとき , すて、に保存側のポイン タは更新済みなのて、 , 更新しないように気 をつけて List 43 のように書きます。左シフ トのときは右下から描くことにしたのて , 右端の処理を手直しします。左シフトの場 合は保存された右端の端数が左のバイトに 52 C MAGAZINE 1 2 8 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 17 : 18 : 20 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 左右のこほれは切り捨てる 1 : VOid far *farshift(int count, word length, void far *dst) int countr; byte cmp, tmp ; byte far *src = (byte far *)dst; if (count 〉の { 〃右シフト count & = 0X07 ; countr = 8 ー count; cmp ニ *src くく countr; *Src = *src 〉 > count; for ( int i = 1 ; i く length; i + + ) { SI'C 十十 ; t 叩 = *src くく countr; *src = cmp ー (*src 〉 > count) : cmp ま t 叩 ; } else ( / / 左シフト count ー —count ; count & = 0X07 ; countr = 8 ー count; for ( int i = 1 : i く length; i + + ) { *src = (*src くく count) ー (*(src + 1) > > countr) : src 十十・ *src = (*src くく count) : return dst; ティスティネー イメージの保存と描画時のずれ xdiff ション一書き込み時に必要なずれ ソース dx d iff diff diff おきます (List 44 ) 。 もうひとつのアプローチとして , ストア 時に全部左にシフトしてしまい リストア 時に全部右シフトするという方法も考えら れます (Fig. 12 ) 。これだとモデルとしては 単純になりますが , リストアの右シフト時 に元の保存情報をシフトて、きないのて、 , テ ンボラリが必要となります。 まず指定されたメモリ領域を左右にシフ トする関数を書きます。簡略化して , シフ ト数は 0 ー 7 に限定します。左右からこばれた 分は切り捨てられます。右シフトを正 , 左 シフトを負のシフト数として与えることに します (List 45 ) 。これを使って List 46 のよ うに定義しておきましよう。 保存するときには , 左シフトしかありえ

3. 月刊 C MAGAZINE 1992年8月号

うことにします。 List 33 ぐらいあれば十分 はバイト単位て、行うのて、奇数バイトと偶数 て、しよう。通常使用て、ここまて、要求される バイトて、書き込むパターンを切り換えます。 ラスターオペレーション List 29 のようにしてバイトに分解してお ことはないと思います。 き , pat Cx& 1 ] て、偶数奇数をふるい分け ラスターオペレーションの演算自体は , 定義そのままて書けるて、しよう。たとえば ます (List 30 ) 。あとは boxfill の hline を hlin 点や線を引くときに , 画面と論理演算を eTone に置き換えて , List 31 のようにして したい場合があります。よくある例として XorBit ならば , やれば , すて、に画面上にある図形の上に矩 は矩形領域を示す枠を移動したり , 直線を pat src dst ; 引くときにガイドラインとして登場するラ と書けます。これを VRAM に書いてやらな 形の網を描画て、きます。 バーバンドなどの XOR 演算をするものて、し いといけないのて、 , スクリーンのマスクを よう。 XOR 演算は 2 回かけると元に戻るの byte mask として , て、 , 非常に便利て、よく使われます。 ラスターオペレーションの演算 円も描いてみます。中心座標を xc , yc 半 ラスターオペレーションは , 理論的には 径を r として , 1 / 8 円の座標を計算します。計 ソース , ディスティ不一ション間の論理ー寅 算された座標を中心に対称な位置に点をプ 算なのて、その数は膨大なため , とても全部 ロットして円全体を完成させます (List 32 ) 。 こて、は代表的なものを扱 は扱えません。 円の描画 円 1 : byte calcROP(byte src, byte dst, \ byte mask, int mode) 2 : 4 : byte 、 pat; 5 : switch (mode) { 6 : case XorBit: pat ニ src 今 dst; 8 : 9 : break : ー 10 : case ClearBit: ー 11 : pat 0 ; を 12 : break; ー 13 : case SetBit: : 14 : pat = 1 & src; break; ー 16 : case CopyBit: Ent = src; break; ー 19 : case NoopBit: : 20 : ニ dst; ー 21 : break ; ー 22 : case AndB it : src & dst; 亂 23 : ー 24 : break; cas e AndReverseB i t : ー 25 : pat = ¯dst & src; ー 26 : ー 27 : break ; ー 28 : case NorBit: pat = src ー dst: : 29 : ー 30 : break : : 31 : case EquivBit: ト 32 : pat = src 。 dst; い 33 : break; case InvertBit: pat に¯dst; : 35 : ー 36 : break : : 37 : case XorReverseBit: pat ・ = src ・ dst; : 38 : break ; ー 39 : ー 40 : case CopYlnvertedBit: ー 41 : pat = src; ー 42 : break ; case AndInvertedBit: src & dstv 44 : break; ー 45 : case XorI nvertedB i t : ニ src dst; ー 47 : break : case NandBit: ー 49 : ー 50 : break; を 51 : default: ー 52 : 〕 t dst; ー 53 : break ; : 54 : ー 55 : return & mask) ー (dst & mask) : ー 56 : 7 : } 1 : void circle(int xc, int yc, int r, int C010r ) 3 : int Xi 4 : int yi 0 ; 5 : int S = r; 6 : while ()i > = (i) { 7 : 8 : putPixel()c + xi, yc + yi, 0010r ) : putPixel()c + xi, yc ー yi, C010r ) ; 9 : putPixel()c ー xi, yc 十 yi, C010r ) : 10 : putPixel()c ー xi, yc ー YI, C010r ) : 11 : putPixel()c + yi, yc + xi, C010r ) : 12 : putPixel()c + yi, yc ー xi, C010r ) ; 13 : putPixel()c ー yi, yc 十 xi, C010 ト ) : 14 : putPixel()c ー yi, yc ー xi, C010r ) ; 15 : 16 : S ー = yi * 2 + 1 : 17 if (s くの ( Xi— 20 S 十 = Xi * 2 ; 21 22 ラスターオペレーションで使用するもの 1 : enum { ClearBit, AndBit,- AndReverseBit, CopyBit, AndInvertedBit, NoopBit, XorBit, NorBit, EquivBit, InvertBit, XorReverseBit, CopyInvertedBit, 3 : XorInvertedBit, NandBit, SetBit } ; ラスターオペレーションを使って点を打つ dst; 1 : VOid putPixPlane(int x, int y, int plane, int mode) 3 : byte src, dst; 4 : byte far *aplane; 5 : aplane = (byte far *)MK_FP(VramSegCplane], y * HORBYTES + (x 〉 > 3 ) ) : 6 : 0X80 〉〉 (x & 0X07 ) ; 7 : *aplane = caIcROP(src, *aplane, srcs mode) ; 8 : 48 C MAGAZINE 1992 8

4. 月刊 C MAGAZINE 1992年8月号

ー丿う 別ラ入 プ成 イ乍 一フィ イ フ ラ グ 特集 指定されたメモリ領域を左右にシフト ( 定義 ) void far *dst) 1 : void far *farshiftr(int count, word length, return farsh i f t (count, length, ds t) : 3 : 5 : void far *dst) 6 : void far *farshiftl (int count, word length, return farshift(-count, length, dst) : 8 : Fig. 12 いっきに左シフトする方法 指定されたメモリ領域を左右にシフト ( 保存 ) 1 : for (int p = 0 : p く = MAXPLANE; p + + ) { 2 : for (int py = sy; py ← ey; py + + ) { 3 : 4 : 5 : farshiftl ()x & 0X07 , Size, imageCp]) ; 6 : 7 : 保存するときには , 左シフトしかありえ ません。というか , 左にシフトして保存イ メージの開始点をバイト境界に強制するの て、す 0List 47 のような感じにして保存する ときに左にそろえます。また , このとき横 幅 (xsize) に 1 を足して 1 ラインの右端にあふ れたビットを受け止めるためのバッフアを 用意しておきましよう。 こうしておけば処 理を少しは簡潔にて、きます。 書き込み時は右シフトしか発生しません が , 保存したポインタをそのまま使うと保 存したものが壊れてしまうのて、 , 1 プレーン 処理するごとにテンボラリにコビーしてや らなければなりません。 (byte far * ) farmalloc (size) ・ tmp として , 1 プレーンのサイズ分のテンボラリ を確保します。 PC ー 9801 の場合 , 最大 32 , 00 0 十 400 バイトが必要ということになります。 あとは右に必要なだけシフトして , 左端 , 間 , 右端を順番に描きます。 1 ライン描き終わった段階て、 , 保存された イメージの次のラインに移るわけて、すが , これは xsize と等しいのて、そのまま加算して やればいいわけて、す ( List 48 ) 。終わったら farfree(tmp) ・ と忘れずにメモリを解放しましよう。 当然 1 バイトの場合の処理も必要て、すが , 左右のマスクを合成したマスクと合成して , ただ描けばよいだけなのて、簡単てしよう。 折衷案として , ストア時に左シフトし , リ ストア時には右シフトしながら描く方法も 考えられます。 実際の使用に際して , ウインドウの下の リストアのように元の位置に描き戻すこと が圧倒的多い場合や , カードゲームなどの ようにストア位置とリストア位置になんら 特集 PC ー 98 田グラフィックライプラリ作成入門 53 次のテータ 違う列のテータが同じ ノヾイトにきて都合か悪い バッフアをとっておけば はみ出した分と次が重ならない 指定されたメモリ領域を左右にシフト ( 書き込み ) (int p = 0 ; P く = MAXPLANE; P + + ) { 1 : for 2 : src ニ tmp; fmemcpy(src, image[p], size) : 3 : dst = (byte far *)MK-FP(VramSegCp], offset) : 4 : farshiftr()x & 0X07 , size, src) ; for (int py = sy; py く = ey; py + + ) { 6 : / / 左端を描く 7 : ニ (*src & maskL) ー (*dst & mskL) ; 8 : *dst / / 間を描く 9 : if (dsize > 2 ) ( 10 : fmemcpy(dst + 1, src + 1, dsize-2) ; 11 : 12 : / / 右端を描く 13 : *(dst + dsize-l) 14 : maskR) : (*(src + ds ize-l) & 盟 s ) ー (*(dst + dsize-l) & 15 : dst + = HORBYTES; src 十 = xsize; 17 : 18 : ピットマップ保存 ( 定義 ) 1 : struct imagerec ( / / 福、高さ 2 : int width, height; / / バイト左端からの差 3 : int xdiff; / / 横のパイト数 4 : word xsize; / / 全体のパイト数 5 : word size; byte far * ptr[MAXPLANE + 1]: 〃 bitmap image へのポインタ 6 :

5. 月刊 C MAGAZINE 1992年8月号

などと , おおらかな気持ちて、スケルトンを 書くと , List 39 のようにして保存してや り , List 40 て、再描画する , となるて、しよう か。これらはエラーチェックもなにもない のて、実用的て、はありませんが , それなりの 動作が期待て、きるて、しよう。 しかし , これて、はちょっと貧弱て、す。ど うせならやはりドット単位て、セープ / リスト アしたいと考えるのが人情かと思います。も ちろんバイト単位て、十分て , スピードを要 求される場合にもバイト単位の転送のほう がよいにきまっています。当然て、す。が , グラフィックを扱うと宣言している以上そ れて、は納得いかないというものて、しよう。 これもまた人情かと。 、ドット単位で 保存は , どのみちバイト単位て、しかて、き ないのて、 , バイト単位版との差はそんなに ありません。 リストアは少しめんどうて、す。ドット単 位て、扱うということは , 元から画面に描か れているものと合成しなければならないと 演算やらマスクを切ったりめんどうなこと このうえない。しかし , やらないといけな いのて、 , 考えましよう。 方針を決めます。保存された情報に着目 すると , 保存した矩形の左端とバイトの左 端の間にはおそらくずれがあるて、しよう。 描くときの座標と保存されたもののバイト 左端からのずれに応じてシフトしながら画 面と合成していくことになります。ちょう ど一致すればたいした苦労はないのて、すが , そうはいきませんね。右にシフトしなけば 矩形領域の保存 IS ラスターオペレーションを使って円を描く 1 : void circlePlane(int xc, int yc, int r, int plane, int MOde) 3 : 4 : 5 : putPix 円 ane()c + yi, yc + xi, plane, MOde); Fig. 9 あふれた部分を次へ送る →右シフト 3 ピット 1 0 1 0 1 0 0 1 0 1 0 1 0 1 0 0 0 0 1 3 ピットあふれる 左に 8 ー 3 = 5 ピットシフトする 1 1 0 0 0 0 1 1 1 1 右シフト 3 ビットしたときにあふれたものと同じ Fig. 10 書き込みが 1 バイトのときにおきる不都合 書き込みたい部分 ■■ 0 第 右 3 ピットシフトまでは平気 4 ビット以上右シフトするとはみだす 2 八イトにまたがっている 左に 2 ビットシフトまでは矛盾しない 左に 3 ヒット以上シフトすると 1 ピットになってしまう いけない場合と左シフトが要求される場合 も当然あります。 気が遠くなってきましたか ? そうて、し よう。て、もまだまだこれからて、す。 これは , 単純に場合分けしてしまいまし よう。ずれを diff とします。シフトするとあ ふれた分は失われしまいます。そりゃちょ っと困るというのて、 , あふれた分を次の処 理に送るために反対のずれを , diff (diff > 0 ) ? 8 int rdiff とします。 8 十 diff ; / / 逆シフト数 左端 , 右端には余分なものがいっしょに 保存されています。それをそのままにして いると禍根を残すのて、 , マスクをかけて画 面と合成します。左右のマスクは , hline の ときと同じものて、 , byte maskL = 0xFF > > (sx&0x07) ; 1 : for (int p = 0 : p ← MAXPLANE; p + + ) { dst ニ imageCp] ー (byte far *)farmalloc(size)); src ニ (byte far *)MK FP(VramSegC ] , offset) ; for (int py ニ sy; py くニ ey; py + + fmemcpy(dst, src, xsize) ; src + = HORBYTES; dSt 十 = xsize; 8 : 7 : 6 : 5 : 4 : 3 : 2 : 50 C MAGAZINE 1992 8 矩形領域の再描画 1 : for (int p = 0 : p く = MAXPLANE; p + + ) { src = ; dst = (byte far *)MK-FP(VramSegCp], offset) ; for (int py = sy; py ← ey; py + + ) { fmemcpy ()s t, s rc, xs i ze ) ; src 十 = xsize,• dst + = HORBYTES; 8 : 7 : 6 : 5 : 4 : 3 : 2 :

6. 月刊 C MAGAZINE 1992年8月号

母音を省略すると発音しにくくなるもの て、すが , 伝統的に C て、使われている名前に は , 母音が含まれていないものもあります。 たとえば文字列処理関数 , vm lock strcmp strcpy などは , フルスペルて、書けばそれぞれ , string compare string copy になるて、しよう。母音を抜いたうえに短く しています。しかし , cmp は compare 以外 に , cpy は copy 以外に誤解することはなさそ うて、す。 あなたが名前をつけるときには , 母音を あまり省略しないように注意しましよう。 もしも省略するときには , 自分て、声をあげ て発音して , 読みにくくないか調べましよ 名前は異なるものを区別するために使い ます。この名前の働きをはっきりと意識す ることは名前をつけるうえて、大切なことて、 す。たとえば , 次の関数宣言を見てくださ copystr(char * strl, char * str2) ・ 関数名が c 叩 ystr て、 , 引数が文字列て、すか ら , どうやら文字列のコピーらしいて、すね。 ところて、文字列 strl を str2 にコピーするのて、 しようか。それとも逆に str2 を strl にコヒ。ー するのて、しようか。悩みますね。次のよう に書いたらどうて、しよう。 copystr(char * src, char * dst) ・ src は source の略て、 , 「源」という意味 , ds t は destination の略て、 , 「目標先」という意味 て、す。それぞれ , ソースとデスティネーシ ョンと読みます。引数を strl, str2 と書くの て、はなく , src, dst と書くことて、 , 引数の役 割りをはっきりとさせています。 この関数の場合 , 引数は両方とも文字列 て、あり , いわば似た顔をしているわけて、す。 違し陸はっきりさせる名前 104 C MAGAZINE 1992 8 そこに似た名前 strl, str2 をつけるのはあま りよくありません。ふたつの引数の役割り の違いをはっきりさせる名前をつけるのが よいのて、す。 次の関数宣言はどうて、しよう。 samestr(char * strl,char *str2) ・ 関数名が samestr て、すから , きっとふたつの 文字列が等しいとき , この関数は 1 を返すの て、しよう。この場合には引数を取り違えて も支障はありませんから , 名前 strl, str2 て、 困ることはありません。 ちなみに , src , dst は両方とも母音を省略 しています。これが読みやすいか読みにく いかは意見が分かれるところかもしれませ ん。 source, destination という名則のほうが はっきり区別て、きますが , いかんせん長す ぎます。とくに destination のほうはスペル を間違える恐れもあります。それに src, ds t は ( 慣れていれば ) 誤解の恐れはないように 思います。 関数の名前の一覧て、す。 ングの工ッセンス」て、私が作った仮想メモリ てください。これは , 先月号の「プログラミ これと似たことがあります。次の関数を見 あることを示しています。プログラムて、も 私の名字「結城」は私が「結城家」の一員て、 共分を持った名前 仕事て、す。 実際のプログラムに応用するのはあなたの る見方のコツをあなたに伝えることて、す。 稿て私がて、きるのは名前の善し悪しに関す われる名前を選ぶことが必要なのて、す。本 あなたが考え , あなたが判断して最善と思 るわけて、はありません。プログラムを書く い作業て、す。必ずしも画一的な解決策があ な矛盾する要求の中て、行わなければならな 読みにくくなる・・ 。名前づけはこのよう ると長くなりすぎる , 短くしようとすると 違いをきわだたせる名前をつけようとす open close vm alloc free vm unlock vm modify release vm modified errstr V m は , プレフィックスは接頭辞 , サフィック の、、 mem クはサフィックスて、す。日本語て、 pen の、、 vm 〃はプレフィックス ,close mem をサフィックス ( suffix ) と呼びます。 vm 0 ス (prefix) と呼び , 後ろにつける場合 , それ う。前につける場合 , それをプレフィック 名前に共通部分を持たせるようにしましょ よろしいて、すか。同じ仲間の関数群には 一貫性がないからて、す。 「何か変だ」と気がっくて、しよう。関数名に らない人て、も , List IA に比べて List IB が この関数がどんな動きをするかまったく知 List IA と List IB を比較してください からて、す。 るとは思えません。名前に共通部分がない とてもこれらが同じ一家に所属してい というバラバラの名前だとしたらどうて、す modify vm m unlock vmlock free memory v alloc close mem vm open これがもし , るのて、す。 て、あることがすぐにわかるようになってい の関数たちが「仮想メモリ関数一家」の家族 すなわち , 関数名の冒頭を見ただけて、 , これはこの関数たちの「名字」にあたります。 の関数の頭に、、 vm クがくつついています。 何か気がつきませんか ? そう , すべて

7. 月刊 C MAGAZINE 1992年8月号

」丿う 別ラ入 プ成 c--o イ乍 一フィ 0 ク イ フ グ さそうて、す。点を打つ目的のビットをマス (pat & mask) それて、は , ラスターオペレーションを使 (dst & &mask) ; ク , すて、に描かれている VRAM の内容を ca となります。この手のルーチンは独立させ って点を打ってみます。グラフィックプレ lcROP に渡して返り値を VRAM に書き戻し ておいたほうが後て、別のところから呼べる ードウェアの性格を考えて , ーンというハ ます (List 35 ) 。また , line 関数も , プレーンごとの演算にしておくのが都合よ のて、便利て、す (List 34 ) 。 void linePIane(int xl, int yl, int x2' ラスターオペレーションを使って線を引く int y2, int plane, int mode) として putPixel を putPixPlane に置き換えれ ばそのまま応用がて、きます。 さらに hline, vline も書き換えましよう。 こっちは単なる置き換えというわけにはい きませんが , 基本的には同じことて、す (List 矩形も box と同様に hlinePlane, vlinePla ne て、書き直すのはとても簡単てすね ( List 3 7 ) 。円も同様にして , List 38 のようにして やれば , 万事 Ok て、しよう。 1 : void hIinePIane(int sx, int mode) int sy, int ex, int plane, 3 : maskL, maskR : byte pat, src, dst, 4 : word dx, xl, x2; byte far *aplane; 6 : / / sx く ex を仮定 7 : 8 : xl = sx 〉 > 3 ; 9 : x2 = ex 〉〉 3 ; 10 : dx = x2 ー xl; 11 : maskL = MASKTBLL[sx & 0X07 ] ; 12 : 皿 s 駅 = MASKTBLR[ex & 0X07 ] ; 13 : aplane = (byte far *)MK FP(VramSegCplane], SY * HORBYTES + xl); 14 : if (dx = の ( 15 : *aplane = calcROP(maskL & maskR, *aplane, mode) ; 16 : } else { 17 : if ()x = 1 ) ( *aplane = calcROP(mskL. *aplane, mskL, mode) : 20 : aplane 十 + : *aplane = calcROP(mskR, *aplane, s , mode); 21 : } else { 22 : *aplane ニ calcROP(mskL, *aplanet, maskL, mcde); 23 : 24 : apl ane + + ; for (int i ニ 1 : i く dx; i + + ) ( 25 : *ap 1 e cal cROP(0xFF, *ap 1 ane, 0xFF, mode) ; apl 町 ie + + *aplane = calcROP(mskR, * 叩 1 e , s , mode) : 29 : 30 : 32 : } 33 : 34 : VOid vl inePlane(int SX, int sy, int ey, int plane, int mode) byte pat, src, dst; byte far *aplane; / / sy く ey を仮定 39 : src = 0X80 》 ()x & 0X0 の ; aplane = (byte far * ) 」 P ( Vr 明 g [ pl e 工 sy * HORBYTES + ()x > 〉 3 ) ) : 41 : for (int py = sy; py ← ey; py + + ) ( *aplane = calcROP(src, *aplane, src, mcde) : aplane + = HORBYTES ; 45 : 46 : } 36 ) 。 矩形領域の保存と描画 矩形て、区切られたビットマップのメモリ への保存と描画は多くの場面て、必要とされ ます。ゲームを作っていてウインドウを出 すときに下の領域を保存し , 後て、リストア したい場合や , グラフィックツールを作っ ていて領域コピー機能を実現する , などに 始まり , ちょっと気のきいたことをグラフ ィックて、やろうとすると必要となってきま す。 メモリを確保して VRAM の内容を保存 し , また指定位置に書き戻す , という簡単 そうな言葉のわりにはけっこうめんどうな のてす。たくさんの罠が待ちかまえていま す。グラフィックプレーン方式てビットを 扱うのて、 , バイトの境界あたりの処理がな かなかおおごとになってしまいます。初め からそんなことを考えていても跡があかな いのて、 , まあ , とりあえず簡単なスケルト ンて、も書いてみましよう。細かいビット操 作はあと回しにして , とりあえずバイト単 位のルーチンを軽く書いてみましよう。 バイト単位 ( 8 ドット単位 ) ならば , 文字列 の操作や 2 次元配列の操作となんら変わると ころはないのて苦もなく書けると思います。 特集 PC ー 98 田グラフィックライプラリ作成入門 49 28 : 7 ラスターオペレーションを使って矩形を描く int mode) 1 : void sx, int sy, int ex, lnt ey, int plane, hIinePlane(sx, sy, ex, plane, : 3 : 4 : hline 円 ane(sx, ey, ex, plane, mode) ; ⅵ ine 円 ane(sx, sy, ey, plane, mode) : 6 : ⅵ ine 円 ane(ex, sy, ey, plane, mode) ; 7 : 9 : int 10 : void llPlane(int sx, int sy, int ex, int ey, i nt p lane, for (int dY = sy; dY く = ey; dY + + ) ( hl inePIane(sx, dy, ex, 01 聞 e , mode) : 13 : 14 :

8. 月刊 C MAGAZINE 1992年8月号

C MAGA VOid $memset(VOid C,Size n); Char tstrerror(int errnum); size_t strlen(const char ts); 13 日付と時間く time. h > CIÆKS_PER_SEC NULL clock_t time_t S1ze_t struct tm clock—t clock(void); 01 1 ー 727 ー 8556 札幌 , 帯広 , 旭川 富山 , 金沢 082 ー 221-4505 米子 , 岡山 , 広島 , 0878 ー 37 ー 2640 徳島 , 高松 , 松山 , const struct tm *timeptr ) ; const Char *format, size_t strftime(char *s,size_t maxsize, struct tm tlocaltime(const time—t *timer); struct tm tgmtime(const time_t ttimer); char tctime(const time_t ttimer); char tasctime(const struct tm *timeptr); time-t time(time—t ttimer); time_t mktime(struct tm *timeptr); double difftime(time—t timel,time—t time の ; Table 1 情報処理技術者試験センター支部一覧および試験地 支部名 北海道 東 関 中 近 中 四 九 沖 北 東 部 畿 国 国 州 縄 所在地 ( 財 ) 北海道環境科学技術センター内 001 札幌市北区北 24 条西 14 ー 8 ー 5 天満橋八千代ビル別館 6 階 540 大阪市中央区天満橋京町 2-6 タカシマ名古屋ビル 8 階 460 名古屋市中区栄 5 ー 26 ー 39 世界貿易センターピル 7 階 105 港区浜松町 2-4 ー 1 佐新ピル 201 号 980 仙台市青葉区本町 3 ー 5 ー 3 テレホンサーヒス 那覇商工会議所ピル 2 階 900 那覇市久米 2 ー 2 ー 10 福岡商工会議所ピル 7 階 812 福岡市博多区博多駅前 2 ー 9 ー 28 セントラルビル別館 7 階 760 高松市亀井町 4 ー 12 第 3 ウ工ノヤピル 3 階 730 広島市中区鉄砲町 1 ー 20 電話番号 03 ー 3436 ー 1321 022 ー 227 ー 0901 担当試験地 埼玉 , 千葉 , 東京 , 水戸 , 宇都宮 , 前橋 , 秋田 , 山形 , 郡山 青森 , 盛岡 , 仙台 , ハ王子 , 横浜 , 厚木 , 新潟 , 長野 , 甲府 , 静岡 052 ー 261 ー 6818 名古屋 , 岐阜 , 豊橋 , 06 ー 946 ー 6301 福井 , 京都 , 大阪 , 神戸 , 姫路 , 和歌山 山口 高知 092-472 ー 4575 福岡 , 北九州 , 佐賀 , 宮崎 , 鹿児島 長崎 , 熊本 , 大分 , 0988-62-2137 那覇 03 ー 3591 ー 0429 注 : 上記各支部で案内書・願書および試験科目説明書を配布します。受け付け時間は午前 9 時から 午後 5 時 15 分まで。土・日・祝祭日は休業 「 QFM PLUS Ver. 1 . 0 」 クレッセンドカンノヾニ クレッセンドカンノヾニーは , QuickBASI C, MS-BASIC 7 対応の ISAM ライプラリ 「 QFM PLUS Ver. 1 . 0 」を発売した。 同ソフトは ,QuickBASIC または MS-BA SIC 7 のプログラム上からデータベース管理 を行うための B 十ツリー方式の ISAM ライプ ラリ。リレーショナルデータベース dBASE Ⅲの各種ファイルにも対応し , 同ライプラ リを使用して開発されたアプリケーション は , dBASEIII とデータの共有 , 相互利用が 可能となる。おもな特徴は以下のとおり。 ・レコード型の dbf, 可変長テキストを扱う dbt, ファイル検索用インディックスを管 理する ndx など , dBASE Ⅲの各種ファイ ルを利用可能 ・ QB アドバイザ , QuickHelp 対応のオンラ インヘルプを装備 ・インタブリタ , コンパイラの 2 種類の数値 演算ライプラリに対応 ・テキスト入出力 , プリンタコントロール , 文字化け処理などをサポートする QFMto olBOX ( PC ー 9801 専用インタフェイスルー チン ) を装備 ・ ATOK, 松茸 , VJE-ßなど各種 FEP に対 ・スタンドアローンライプラリとクイック ライプラリの 2 種類のライプラリを搭載 く動作環境 > ・対応機種 PC ー 9801 シリーズ ・対応 OS MS-DOS Ver. 2.11 以上 ・対応コンパイラ QuickBASIC Ver. 4.5 News Square 147 MS-BASIC Ver. 7. IJ

9. 月刊 C MAGAZINE 1992年8月号

られている型 ・不完全型 オプジェクトのサイズ情報が欠け ている型 こて、「完全型」なる用語は筆者の創作て、 あることに注意されたい。 ANSI C 標準に は , 「完全型 (complete type) 」という用語は 登場しない。しかし , 形容詞としての「 com plete 」 , もしくは「 completed 」て、あれば何度 か登場する。そこて、 , 以下説明の便宜上 , 「完全型 (complete type) 」という用語を「オ プジェクトを記述する型て、 , サイズを決定 するために必要な情報が与えられている型」 という意味て、用いる。 この 3 分類は , ある観点て、はこのように型 を分類て、きるというだけて、あり , 数ある分 類法のひとって、しかない。これ以外にも , ANSI 標準は型に関して実にさまざまなグル ーヒ。ングを行っており , 特有の名前を与え ている。ただし , このグルーヒ。ングは複雑 に絡み合っていて , 単純なネスト構造にな っているわけて、はない たとえば , 「パソコン」を分類する場合に , 「ラップトップ / デスクトップ」とか , 「 16 ビ ットマシン / 32 ビットマシン」とか , いろい ろな観点が考えられる。それぞれの分類ご とに含まれてくる機種の集合が変わるだろ う。そしてそれらの分類は単純な階層構造 て、はないことも理解て、きるだろう。それと 同じて、 , 型に関しても種々の異なった分類 を行える。 , こて、は資料としての意味もあり , ANS I が規定しているグルーピングとその名前を 順次あげていくが , なかには実質的な意味 をほとんど持っていないものもあることを ・基本型 (basic types) こともて、きる。 ANSI によれば , 型は次の 4 種に分類する 基本型と派生型 お断わりしておく。 ・列挙型 (enumerated types) ・ void ( 不完全型 (incomplete type) ) ・派生型 (derived types) 1 番目の基本型 (basictypes) は , あまり 見かけない用語て、あろうが , これに関して は内容を Fig. 1 に示す。「 basic 」の意味は , それらが組み込みの型として C 言語に備えら れていることからきているものと思われる。 実際 , void を除くすべての組み込み型が ba sic types としてあげられている。この basi c type は四つに細分され , char, signed お よび unsigned の整数型 (integer types) , そ して浮動小数型 (floating types) とから構成 される。そして , それぞれには Fig. 1 に示す 組み込みの型が従属する。 こて、 , char/signed char/unsigned ch ar が奇妙な方法て、分類されていることに気 づかれるだろう。この分類は符号つき / 符号 なしの整数型系列の説明を楽にするための 便宜的なものだと考えられる。たとえば sig ned integer types だけを取って考えると , signed char, short int, int, long int て、は , そのオプジェクトに格納される値の表現範 囲はひとっ後の型の部分範囲になっている ことが要求される。同様の制約は unsigned integer types にも , floating types にも適用 される ( 「部分範囲」という場合 , ひとつ後の 型とまったく同じ表現範囲て、もかまわない とに注思 ) 。これが signed char と unsign ed char をそれぞれ integer types へと組み込 んだ理由て、あろう。 その結果 , (plain) char が独立してしまっ た。しかし , ANSI にはこれとは別に「文字 型 (character type) 」というグルーヒ。ングが ちゃんと存在していて , それは char と signe d char と unsigned char て、構成されるという 規定もある。これは basictypes の分類とは 直交した概念て、ある。また , char/signed c har/unsigned char は同じ記憶容量を確保す べきことが定められている。 2 番目の列挙型 (enumeration types) は , いわゆる enum 型て、ある。注目すべきこと 員 N 引 Cå more は , この分類に従えば列挙型は basictypes と同等の立場に存在する点て、ある。列挙型 は組み込みの型て、はなく , その実体はプロ グラマが定義するものなのて、 , 1 番目の ba sic types<' はあり得ない。一方 , enum はそ れ独自て、型を構成し , ほかの型から派生す ることはない。このため 4 番目の派生型にも 属さない。そして enum は不完全型て、はない のて、 , 3 番目の void とーまとめにして論じる ことはて、きない。結局ほかの 3 種と同列て、独 立した立場を確保することになる。 3 番目の void については , 「値の空集合を 構成する」ことと , 「不完全型 ( の 1 種 ) て、あ り , 完全 ( 型 ) にすることがて、きない」という 定義が与・えられている。 4 番目の派生型 (derived types) は , 最初の 三つ , すなわち基本型 , 列挙型 , および vo id から「派生」させられる型て、ある。「派生」さ せる手段としては以下にあげる 5 タイプが存 在する。 ・配列型 (array type) ・構造体型 (structure type) ・共用体型 ( union type) ・関数型 (function type) ・ポインタ型 (pointer type) このうち , 最初の 3 タイプ , 配列型 , 構造 体型 , 共用体型 , および最後のポインタ型 Fig. 1 basic types の定義とその階層 ・ basic types Char ・ signed integer types signed char short int int long int ・ unsigned integer types unsigned Char unsigned short int unsigned int ” unsigned long int ・ floating types ” float ” ” doub 厄” "long double" ANSI 引 more 111

10. 月刊 C MAGAZINE 1992年8月号

択をしたて、しよう。 -ALZ [ 訳注 ] こにも , サードバーティーと いう語の誤認 , Microsoft 社に対する不適切 な特別視がみられる。正しくは , Microsof t も one of サードバーティーなのだから , ど んな規格仕様のソフトウェアを市場に出そ うと , 自由なのて、ある。もちろん , それに 対するユーザの選択も自由て、ある。 Micros 。 ft がいかに巨大て、 , かっ ( 不幸なことに ) 標 準基本システムの独占供給者て、あっても ( 最 近は DR-DOS なんかもあるが・・ of サードバーティーソフト企業にすぎな という認識を持っことが , PC 界の今後 の健全化のために不可欠て、ある。 286 åDOS-extender Ver. 2.0 Phar Lap Software コンパイラのべンダたちが , 自分たちの 製品に無料の DOS extender をバンドルする ようになったのは , ほんの一年前からて、す。 評論家や識者は , DOS extender を高い価格 て、売って , しかもそれを利用するアプリケ ーションに高価なロイヤリティを義務づけ ていた , PharLap みたいなべンダは , 倒産 するて、あろう , と予言しました。 ところが PharLap は , さらに良質な extender と , テ クノロジの改善て、もって , この難局に対処 しました。 28 引 DOS-extender が , その努 力の成果て、あります。 この extender は , 286 および 386 マシンの 16 ビットプロテクトモードて使えるものて、 , Borland C 十十および Microsoft C Ver. 6. 0 と互換性があります。これらのコンパイラ だけて、なく , 付随のデバッガにもとくに問 題なく対応します。さらに Phar Lap は , ダ イナミックリンクライプラリ (DLL) , 同一 プログラム内て、のリアルモードとプロテク トモード , そして extender を拡張て、きる一 群のルーチンを使うことによって , プロテ クトモードの DOS の下て、のダイナミックリ ンキングの機能を提供しています。 Phar Lap のテクノロジと , すぐれたドキ ュメンテーションは , リアルモードからプ ロテクトモードへの移行の容易さを , 一貫 して強調しています。同社のその努力は , めて、たく報われたと言えるて、しよう。 Borl and と Microsoft に加えて , すべての 386 D OS C コンパイラが , 同製品をサポートして 良質なライプラリバッケージは , 対照と Tu rbo Powe r Softwa re Async Professional Ver. 1 .02 いるのてすから。 -ALB るのて、 , COM8 が ARC-NET のバッファゾ は , 多様なハードウェアをサポートしてい もある。さらにこのライプラリバッケージ し , ZIP と LZH ファイルを解凍するルーチン トコルを扱うルーチンも当然含まれている ODEM, ZMODEM, Kermit など各種プロ 富なツール類を提供する。 XMODM, YM ッケージは , TurboPascaI のユーザに , 豊 すべて , 簡単に満たしている。この通信パ Async Pr0fessional は , これらの基準を っと下の価格て、 , それを入手したいと思う。 ぎみのクレジットカードの許容額よりもす める。しかもわれわれは , すて、に買いすぎ 使えるほどの汎用性を持っていることを求 そのライプラリが , 他のプロジェクトにも にライプラリを買うのだが , しかし同時に 求める。われわれは特定の開発課題のため ーションを見る必要がない という状態も いったんインストールしたらドキュメンテ ンやクラスが非常に良く設計されていて , ョンを求める。しかしまた同時に , ルーチ 知りたいから , 充実したドキュメンテーシ そこに盛り込まれている背景的な考え方も われわれは , 大量のライプラリを前にして , いうものを研究した精華て、ある。たとえば ーンにあるような , 奇形の PC の場合て、も困 らない ューザのアプリケーション開発を支援す るために , サンプルアプリケーションと , 高度なデバッグッールが含まれている。ま た , ライプラリとツールのソースも , すべ て含まれている。さらに各ルーチンは , オ プジェクト指向のクラスパージョンと , 従 来のプロシジャパージョンの , 両方を提供 円引年」 OLT 賞の発表 29 機能としては , データをその入力時点て、ェ レータへの入力にすることもて、きます。新 あるいはバンドルされている C のコードジェ アプリケーションが直接にロードしたり , 帳票の設計に力を入れており , その出力を 新バージョンは , とくに対話画面と , 書式 厚いマニュアルて、解説されています。この え , 合わせて 2 , 000 ページを超える 3 巻の分 ばえて、す。ライプラリは 600 関数近くにも増 Ver. 3.0 も , その評判を裏切らない出来 かに超えて充実していました。 もってやりたいと思うようなことを , はる が , グラフィカルユーザインタフェイスて タベースて、ありながら , 現在ほとんどの人 築されていました。その機能は , キャラク その誰もが褒めそやすインタフェイスは構 ログラマに対する細心の配慮を踏まえて , こういう , プ ロ〕もありましたからね ! メンテーションの重さが 13 ポンド〔約 5.9 キ いう製品の則のノヾーションなんか , ドキュ 評を得ていました。この VermontViews と 能の製品を提供している , という世間の定 カル〕のインタフェイスとしては最も多機 中は , キャラクタベース〔 = ノングラフィ ずいぶん久しく , Vermont Creative の連 Vermont Creative Software Vermont Views Ver. 3 - 0 -RTS している。全体的に見て , この製品の価値