size - みる会図書館


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

1. 月刊 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 :

2. 月刊 C MAGAZINE 1992年8月号

SIGTERM void い signal(int sig,void(*func)(int)))(int); 10 入出力く stdio. h > void va end()a list ap); type va—arg(va—list ap , 亡アの ; void va—start(va—list ap,parmN); va list 9 可変個の実引数く std 9. h > int raise(int si ) ・ int rename(const Char $old,const Char int remove(const Char tfilename); TMP_MAX stdout stdin stderr size_t SEEK SET SEEK_END SEEK_CUR NULL L—tmpnam fpos—t POPEN_MAX PILENAME_MAX BUÆIZ 」 ONBP 」 0 P IOPBF ttmpfile(void ) ; char ttmpnam(char ts); int fcIose(PILE tstream); int ffIush(PILE tstream); PILE tfopen(const char tfilename, const char tmode); FILE *freopen(const char *filename, const char *mode,FILE tstream); void setbuf(PILE tstream,char *buf); int setvbuf(PILE tstream,char *buf,int 1 Ode , size t size) ・ int fprintf(FILE tstream, const char *format,... ) : int fscanf(FILE ・ stream , const char *format,... ) ; int printf(const char *format, int scanf(const char *format, int sprintf(char *s,const char $format, int sscanf(const Char tS, const char 叮 ormat ,... ) ; int vfprintf( FILE ・ stream , C MAGA void free(void tptr); VOid tcalloc(size_t nmemb,size_t size); void srand(unsigned int seed); int rand(void); char "endptr,int base); unsigned long int strtoul(const char *nptr, char ttendptr,int base); long int strtol(const char tnptr, double strtod(const char tnptr,char ttendptr); long int atol(const char tnptr); int atoi(const char tnptr); double atof(const char tnptr); wchar t Size t ldiv_t div t RAND_MAX MB CUR MAX EXIT_FAILURE 11 一般ユーティリティく std ⅱ b. h > void perror(const char ts); int ferror(FILE tstream); int feof(FILE tstream); void clearerr( PILE tstream) ; void rewind(FILE tstream); long int ftell(FILE *stream); int fsetpos(PlLE tstream,const fpos—t tpos); int whence ) : int fseek()I し E tstream,long int offset, int fgetpos( tstream ,fpos—t 第 pos) : size t nmemb PILE tstream); size_t fwrite(const void tptr,size_t size, size—t nmemb 町し E ・ stream ) ; size t fread(void tptr,size_t size, int ungetc(int C,PILE tstream); int puts(const char ts); int putchar( int c) ; int putc( int c , PILE ・ stream ) ; char *gets(char *s); int getchar(void); int getc(FILE tstream); int fputs(const char ts,PlLE tstream); int fputc(int C,PILE tstream); char *fgets(char *s,int n,PILE *stream); int fgetc (PILE ・ stream) ; const char tformat va list ar ) ・ int vsprintf( char 岶 , int vprintf(const char *format,va—list arg); const char *format,va list arg); void tmalloc(size_t size); void trealloc(void $ptr,size_t size); void abort(void); int atexit(void (tfunc)(void)); void exit(int status); char *getenv(const char *name); int system(const char tstring); void *bsearch(const void tkey, VOid *base,size_t size—t size,int(tcompar)(const void 事 const VOid の ) : void qsort(void *base,size t nmemb, size_t size,int(*compar)(const VOid * const void の ) ; int abs(int j); div t div(int numer int denom) ・ long int labs(long int j); ldiv_t ldiv(long int numer,long int denom); int mblen(const char *s,size_t n); int mbtowc(wchar_t *pwc,const char *s, size_t n); int wctomb(char ts,wchar_t wchar); size_t mbstowcs(wchar_t tpwcs, const char ts,size_t n); size_t WCStombS(Char *S, const wchar_t tpwcs,size t n); 12 文字列掾作く st 「 ing. h > NULL SIZe t void tmemcpy(void tsl,const void *s2,size_t n); VOid *memmove(void *sl,const VOid 事 S2 size_t n ) ; char *strcpy(char tsl,const char 2 ) ・ char tstrncpy(char tsl,const char *s2,size t n); char tstrcat(char *sl,const char ま s2 ) ; char tstrncat(char *sl,const char *s2,size_t n); int memcmp(const void *sl,const VOid s2 , size t n) ・ int strcmp(const char *sl,const char s2 ) : int strcoll(const char *sl,const char 事 s2 ) ・ int strncmp(const char *sl,const char 事 s2 size_t n); size t strxfrm(char tsl,const char *s2,size t n); VOid *memchr(const VOid *s,int c,size_t n); char tstrchr(const char ts,int C); size—t strcspn(const char tsl,const char ・ s2 ) : char tstrpbrk(const char *sl,const char ま s2 ) ; char tstrrchr(const char *s,int c); size—t strspn(const char tsl,const char ・ s2 ) ; char tstrstr(const char tsl,const char ・ s2 ) ; char tstrtok(char tsl,const char ・ s2 ) ; 146 C MAGAZINE 1992 8

3. 月刊 C MAGAZINE 1992年8月号

会 moji_pitch() 関数により指定する。この関 数の書式は Fig. 5 のとおりて、ある。したがっ て , m0ji_pitch("100") と指定すれば , 1 イン チに 1 文字入るように水平移動することにな ところて、フォントを変更するごとに文字 サイズやビッチを指定するのはめんどうて、 ある。そこて、通常使用する場合には , した諸々の指定をメモリに登録しておき , 必要に応じてそのメモリの内容を呼び出す 方法をとる。この処理を行う関数が put mo jiset( ) 関数と get_mojiset( ) 関数て、ある。 put_mojiset( ) 関数は , 設定内容を登録す る関数て、あり ,get mojiset( ) 関数は登録し たメモリの内容を呼び出す関数て、ある。 れらの関数の書式はそれぞれ Fig. 6,Fig. 7 のようになっている。 文字セットアサイン番号とは , 設定内容 を登録するメモリの番号と考えていただき 次に割り当てテープルて、あるが , これは 少々理解しづらいものて、ある。まず Fig. 8 を ご覧いただきたい 割り当てテープルとは , 文字セットを待 機させておくバッフアと考えると理解しや すい。この割り当てテープルは 4 個用意され ている。各割り当てに割り当てられている 文字セットは , シフトスイッチにより左表 (GL) または右表 ( GR ) に呼び出して印字に使 用することになる。実際の印字の際 , 左表 と右表のどちらの文字セットが選択される かは , 文字コードの最上位ビット (MSB) の 値による MSB カ : 0 の場合 , すなわち文字。ードの値 が 21h ~ 7Eh または 2121h から 7E7Eh の間の場 合は , 左表に呼び出されている文字セット が印字され , MSB が 1 の場合 , すなわち文字 コードの値が A0h から FEh または AIAIh か ら FEFEh の間の場合は , 右表に呼び出され ている文字セットて、印字される。 文字コードの値は , JIS や EUC などのコー ド体系によってその値が変化してしまう。 120 C MAGAZINE 1992 8 サンプルプログラムの印刷例 Fig. 1 場 Fig. 2 job start( ) 関数の書式 job_start(comlevel, dpi, code) コマンドレベル Char * comlevel : ← - LIPS Ⅱ + の場合 凵 PS Ⅲの場合 ←解像度 LIPS Ⅱ + の場合 240 凵 PS Ⅲの場合 300 ←文字コード体系 操作ノヾネルの設定値 0 』 S コード 1 EUC 2 DEC コード 3 P 日 201 系用』 S 4 AX 系用 J 旧 5 Char *dpi : Char * COde , Fig. 3 moji size( ) 関数の書式 moji size (size) char * size ←文字サイズ Fig. 4 zahyot_unit( ) 関数の書式 zahyot unit(unit) char *unit , ←選択する単位 1 / 720 インチ 2 1 / 1000 ミリ 6 7 1 / 100 ミリ ? 6

4. 月刊 C MAGAZINE 1992年8月号

List 1 78 : ( ← 0X4f73 のコードが入っている 50 : 52 : 53 : 54 : 56 : 58 : 59 : 60 : 61 : 62 : 63 : 64 : 65 : 66 : 68 : 69 : 73 : 74 : 76 : 77 : 83 : 85 : 86 : 88 : 89 : 90 : 92 : 93 : 94 : 95 : 96 : 98 : 99 : 100 : 101 : 102 : 103 : } mojiretsu_kakudai mode() ; zahyot unit("?6") ; size mode(); initlaza() ; j0b ー s ね rt ( ” 31 ” , ” 300 ” , ” 4 ” ) ; Gdpi = 300 ; 55 : #endif system( comm ) ; sprintf(comm, ” /usr/5bin/stty raw く Xs ” , Grcpt_printer-device) ; exit(l); printf( ” can' t fOEEIl printer }n ” ) ; 82 : #ifdef MSDOS 81 : #endif gl—char—set ( ) ; 79 : #ifdef UNIX mojisets(void) exit( の ; job—end() ; kaipage(); mkprint(35, 200 , " mkprint(35, 100 , ”会 moj i-pitch("100") ; nbai ( " 200 " ) : get—moj iset(GOTHIC_SCALABLE) ; mojisets() ; print—maisu("l"); auto—kyocho ( ) ; こが最も重要なポイント * / / * アサインテーブルが異なる * / / * UNIX と MS-DOS では g2—char—set() ; 84 : #endif sel—mojiset("K32M. J83 " ) ; sel—mojiset( ” Minch0-Medium. J83 " ) ; put-mojiset( ” 3 ” , ASSIGN-TABLE) ; seLmojiset("K24G. J83 " ) : put—mojiset("2", ASSIGN-TABLE) ; sel—mojiset("K32G. J83 " ) ; put—mojiset( ” 1 ” , ASSIGN-TABLE) : sel—mojiset( ” K2州 . J83 " ) ; put—mojiset("0", ASSIGN-TABLE) ; return ( の ; put—mojiset( ” 5 ” , ASSIGN TABLE) ; mji—size("1750") : moji—pitch( ” 145"): sel—m0jiset("G0thic-Medium. J83 " ) ; put—mojiset("4", ASSIGN TABLE) : moji—size( ” 1750 ” ) ; moj i—pitch("145") ; これに対し , スケーラブルフォントの場合 開始命令てコマンドレベルを LIPS Ⅲモード まず LIPS Ⅲを使用する場合には , ジョブ タ—(Fig. 1 参照 ) を作成するものて、ある。 を使用して文字を超拡大し道先案内用ポス このプログラムは , スケーラブルフォント List 1 のプログラムを見ていただきたい 意を要する点がいくっかある。 ーラブルフォントを使用する場合には , 注 有の大きさを持たない。したがって , スケ は , フォントの情報はべクトルてあり , 固 にする必要がある。また解像度も 300dpi に設 定する必要がある。この処理を行っている のが job start ( ) 関数て、ある。この関数の書 式は Fig. 2 のようになっている。 したがって , PC ー 9801 て、 LIPS Ⅱ + を使用す る場合には , job start("21' , " 240 " , " 4 " ) ; LIPS Ⅲを使用する場合は , j0b start("31", " 300 " , " 4 " ) ; という指定になる。 また EUC を使用している UNIX て、 LIPS 応用 C 言語 C の道具箱 という指定になる。 j0b_start("31", " 300 " , " 2 " ) ; LIPS Ⅲを使用する場合は , j0b start ( " 21 " , " 240 " , " 2 " ) ; II + を使用する場合には , チ以外て使用する場合は , 文字ピッチを指 また , スケーラブルフォントを固定ピッ るわけて、ある。 ズは , 10 ミリすなわち 1 センチの大きさにな ize ( " 1000 ' ' ) という指定をすれば , 文字サイ なる。この指定をした後て、たとえば moji s ば , サイズの単位は 1 / 100 ミリというこ したがって , zahyotunit("?6") とすれ 4 のようになっている。 unit() 関数てあり , この関数の書式は Fig. ている。この単位を選択する関数が zahy 。 t 単位選択命令によって選択したものになっ ここて、指定するサイズの単位は , サイズ なっている。 数て、ある。この関数の書式は Fig. 3 のように この処理を行っている関数が moji size() 関 の文字サイズも指定しなければならない フォントの選択だけて、は十分て、はなく , そ トの場合 , 固有の大きさは存在しないのて、 , て、ある。前述のようにスケーラブルフォン -Medium. J83〃などはスケーラブルフォント 一方 , 、、 Mincho-Medium. J83〃や "Gothic されている。 て , 縦横の縮小は 2 分の 1 , 拡大は 2 倍と固定 ケーラブル機能は持っていない。したがっ J83 〃などは LIPS Ⅱ + 用のフォントて、ありス ント名を表している。、、 K32M. J83 〃や、、 K32G. この中の sel_mojiset( ) 関数の引数がフォ の選択を行っている関数て、ある。 を見ていただきたい。この関数がフォント サンプルプログラム中の mojisets ( ) 関数 トを選択する必要がある。 ラブル機能をサポートしている文字フォン 定て、ある。これは当然のことながらスケー 次に注意すべき点は , 文字フォントの指 印字後の水平移動量のことてある。 定する必要がある。文字ピッチとは , 文字 これは 応用 C 言語 119

5. 月刊 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

6. 月刊 C MAGAZINE 1992年8月号

ープロクラミング道場 ある。 さて , 先述の【症状】は , 、、嘘〃て、あるこ とがわかったて、あろう。 getchar( ) の呼び 出しは無視されているのて、はなく , 正しく 、、 \ n 〃を読み込んて、いるのだから List 1 の プログラムは , プログラマの命令どおりに 動作したのだ。症状を取り違えると , その 原因を探ることなどて、きるはずはない 【重要】期待する動作をしないプログ ラムの症状を取り違えてはいけない 咳が出るからといって , 必ずしも風邪薬 もしかしたら喘息か が効くとは限らない Dr. 望洋の ストリームとバッファリング もしれないのだから。 ストリームのバッファリング の文字の総称て、ある。 てはない。 C 言語ての空白は , 次の五つ わゆるスペース文字のみを意味するわけ 空白すなわちホワイトスペースは , い 空白 (white space) のバッフアを強制的にフラッシュしようと と fflush 関数によって , 標準入力ストリーム ch=getchar( ) ; fflush(stdin) ・ すなわち , ラッシュする に , 標準入力ストリームのバッフアをフ 【解決策 ? 】 getchar( ) を呼び出す前 のような解答を出した。 かの学生に命じたところ , ほとんどが , 次 このプログラムを修正するように , 何人 'Yf' 'Yn' 'Yt' 'Yv' : スペース (space) : フォームフィード (form feed) 改行 (new line) : 水平タブ (horizontal tab) 垂直タブ (vertical tab) いうことて、ある。 このように変更したプログラムは , なる など私の使用している環境て、は正しく動作 する。 fflush ( ) の呼び出しにより , キーバ ッフアに残っているが掃き出されるのて、 , getchar() によって , キーを 1 文字入力てき るようになる。 しかし , この方針はいただけない。後述 するように , 環境・処理系によっては動作 C 言語ては , ファイルなどの入出力をスト リーム (stream) という概念て扱う。入出力 を円滑化するために , ストリームはバッフ アリングされる。すなわち , 1 文字 ( バイト ) の入出力を行うたびに , ファイルに対して 読み書きを直接行うのてはなく , ある程度 バッファ ( buffer ) に読み書きすべきデータが たまった段階てバッフアの内容を読み書き するのて、ある。 C 言語てのバッファリングには , 以下に示 す 3 種類がある。 (a) 完全バッファリング (fully buffering) 入力 : バッフアがフルになるまて入力が 行われる。バッファルが空になるま て、ファイを読み込むことはない 出力 : バッフアがフルになるまて出力が 行われる。バッフアがフルになるま てファイルに書き出すことはない (b) 行バッファリング (line buffering) 入力 : バッフアがフルになるか , 改行文 字を読み込むまて、入力が行われる 出力 : バッフアがフルになるか , 改行文 ShibataU しない可能性があるのだ。 リダイレクトを使ってみよう。 と確認用の文字をファイルとしたものて、あ て、作成しよう。もちろん , 入力すべき名前 のようなファイルを "shibata" という名前 A> listl く shibataU と実行すると , 標準入力ストリームは , キ ーボ、一ドて、なく , ファイル、、 shibata" に割 り当てられる。すなわち , scanf( ) や getch ar() は , ファイル、、 shibata" から読み込ま れることになる。このように実行すると , ( 私の環境て、は ) またまた getchar( ) が無視 される ( ? ) のて、ある ! ! キーポートからの入力だと正しく動作し , ファイルからの入力て、は誤動作をしてしま うのだ。フラッシュ操作には , 次のような 規則があることを覚えてほしい 【重要】入力ストリームに対するフラ ッシュ操作の動作は定義されない ( 環境・ 処理系やストリームに結び付けられてい るファイルなどによって異なる ) 字を書き出すまて出力が行われる (c) 非バッファリング (unbuffering) バッファリングは行われない 可能なかぎり入出力は直ちに行われる バッファリングの方式を指定するには , tvbuf 関数を使用する。この関数は , 以下 の形式を持つ int setvbuf(FlLE * st 「 eam, char * buf, int mode, Size t size) バッファリング方式に対応する mode には , <stdio. h> に定義されている , 以下の定数の いずれかを指定する。 IOFBF : 入出力を完全にバッファリング IOLBF : 入出力を行バッファリング IONBF : 入出力をバッファリングしない そのほかの引数や , 具体的な機能・動作 などについては , 参考文献 [ 1 ] や , 処理系 のマニュアルなどを参照していただきたい。 なお , setbuf というライプラリも用意されて いるが , tvbuf の機能に含まれるのて、 , あま り利用することはないだろう。 D 「 . 望洋のプログラミング道場 65

7. 月刊 C MAGAZINE 1992年8月号

BorIand C 十十 Turbo C 十十 Q BorIand C 十十 3.0 は , DPMI にだけ対応して , VC 円には対応し ていないというのは事実ですか。 A BorIand C 十十 3.0 は , DPMI にも VCPI にも対応しています。し たがって , VCPI に対応した仮想 8 6EMS ドライバが組み込まれている 場合ても , Windows のエンハンス モードにおける DOS プロンプトて、 も実行て、きます。もし , VCPI 対応 のドライバが使われているのに Bo rlandC 十十が起動て、きないという ことてあれば , メモリ不足の可能 性も考えられますのて、 , 最低限必 要なデバイスドライバ以外はすべ て取り外してから試してみてくだ Q クラスの中でバッフアの大き さを指定するのに const 変数を使い たいのですが , コンバイルエラー になってしまいます ( List 1 ) 。 C 十十では , const 変数は #define の かわりとして定数と同じように使 えないのですか ? A クラス内て、は , 変数の実体を 定義することはて、きません。また , const 変数は宣言と定義を同時に 行わなければなりません。したが って , クラス内て const 変数を定義 することはてきません。この場合 は , 列挙型を使うようにしてくだ さい (List 2 ) 。 Q クラスの static メンバを定義す るために pr ⅳ ate で定義した列挙型 の値を使いたいのですが , コンバ 0 lnformation 行 om 町ⅱ計 Ma れ門 ボーランド 10 : } 13 : ( 15 : } 18 : { イルエラーになってしまいます。 static なメン / ヾから pr ⅳ ate 部の識 別子を参照することはできないの ですか (List 3 ) 。 A private< 定義された識別子 は , クラス定義の内部か , メンバ 関数の中からしかアクセスて、きま せん ( friend 宣言されたものを含 む ) 。したがって , クラスやメンバ 関数の外部て、データメンバを定義 したり初期化するために private 部 の値を使用することはて、きません。 この場合は , public 部て、定義するよ うにしてください。 static なメンバ 関数から private 部の識別子を参照 することは可能て、す。 Q I/O ストリームクラスを使った 出力 ( cout ) と標準入出力関数によ る出力 (stdout) を併用しています が , リダイレクトすると出力順序 が変わってしまいます。なぜでし ようか。 シュするようにしてください 出力後にバッフアの内容をフラッ が , どうしても併用される場合は ーしておくほうが望ましいのて、す どちらを使って入出力を行うか統 ります。ひとつのプログラムては , 力のタイミングがずれることがあ したバッファリング処理により出 ムクラスと標準入出力関数の独立 クデバイスのときは , I/O ストリー 出力先がファイルのようなプロッ 字単位て、フラッシュされますが , ラクタデバイスてあれば出力は文 力を行っています。出力先がキャ 標準入出力関数とは独立して入出 通常 , I / 0 ストリームクラスと A クラス内で const 変数を定義した例 1 : class ( 2 : const int num = 100 : / / Error! char buffer : 3 : 4 : public: 5 : List 1 List 1 を列挙型を使用して修正 1 : class { enum { num = 100 : ) 2 : char buffer Cnum] : 3 : 4 : public: 5 : List 2 クラスの static メンバの定義に p 「 ivate で定義した値を使用した例 1 : c lass ( enum ( SIZE = 256 ) : 2 : 3 : public: static char bufferCSIZE]; 4 : 6 : char rock::bufferCrock: :SIZE]; / / Error! 2 桁の数値を入力して表示するプログラム List 3 List 4 int getdigit() 2 : #include く coniO. h> 1 : #include く ctyre. h> 3 : 5 : 6 : 7 : 8 : 9 : 14 : int c; do ( c = getch() : ) while (!isdigit(c)); return c; 12 : void min() printf("XcXcYn ” , getdigit(), getdigit()) ; 1 : void zin() List 5 List 4 main() の修正 3 : 4 : 5 : 6 : int cl, c2; cl = getdigit() : c2 = getdigit(); printf( ” XcXc*n ” , 01 , c2); Fig. 1 し 6 で期待していた出力 A : : A ( 123 ) : B ( 123 ) c: : C ( 123 ) コンストラクタの呼び出しがうまく行われない例 List 6 A(int i) ( printf("A::A(Xd)Yn ” , i); ) 3 : public: 2 : class A ( 1 : #include く stdio. h 〉 14 : 10 : 9 : 5 : 4 : C obj ( 1 ) : 17 : void min() C(int i): B(i) ( printf("C::C(Xd)h". i); } 13 : public: 12 : class C: ⅵれ聞 1 public B ( B(int i): A(i) ( printf("B::B(Xd)h", i); ) 8 : public: 7 : class B: ⅵ「 t 1 public A ( List 7 引数つきコンストラクタが呼び出せると不都合となる例 12 : public: 11 : class A: virtual public V ( 10 : / / V から派生したクラス A V(int i) ( printf( ” V: :V(Xd)%n ” , i); } 5 : public: 4 : class V { 3 : 〃仮想基本クラス V 1 : #include く stdiO. h> 9 : 7 : 6 : 2 : 162 C MAGAZINE 1 2 8

8. 月刊 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 :

9. 月刊 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

10. 月刊 C MAGAZINE 1992年8月号

は引数を持てません。ひとつのクラスはた かだかひとつのデストラクタしか持てない ということになります。生成の方法がいく つあろうが , 破壊への道筋はひと通りしか ないのて、す。 さて , デストラクタが必要な局面という のはいくつも考えられますが , そのひとつ にポインタをメンバとして持っクラスがあ ります。たとえば , 可変個数の配列を実現 するクラスを考えてみましよう (List (1) 。 この例て、は , クラスの中に array というポイ ンタがあります。コンストラクタにおいて , このポインタに必要なだけヒープからメモ リが割り当てられます。 インスタンスが用なしになる時点 , つま りインスタンスが定義されたプロックを出 るときに , 割り当てられたメモリは不要に なります。 List 11 て、いうと , main( ) を抜 けるときて、すね。このとき , 不要になった メモリを解放しなくても誤動作することは まれて、しようが , そのメモリ領域はほかの 用途に使うことがて、きなくなり , しまいに はヒープを使い果たしてプログラムが停止 してしまうかもしれません。 通常の C 十十の構文に従っていると , ど うしてもメモリモデルの制約にしばられ てしまいます。 C のときと同じように , ス モールモデルて、も far ヒープ上にオプジェ クトを生成したり , 64K バイトを超えるオ プジェクトを使いたいと思うことがある のて、はないて、しようか ? Turbo C 十十や Borland C 十十を使い スモールモデルて、 far ヒープ上にオプジェ クトを生成するには , 拡張されている cla ssfar という記法が使えます。拡張された far クラスを使うときは , クラス内のポイ ンタ型や参照型にはすべて far をつけるよ うにします (List ) 。とくに , far データ 13 : { 16 : } 96 C MAGAZINE 1992 8 ばなりません。 64K バイトを超えるオプジ 場合は , 必ず far クラスにしておかなけれ 上にあるオプジェクトにアクセスしたい C 十十⑩テクニック はほかの用途に使えるようになります。 解放してやれば , array が占めていたメモリ デストラクタが呼ばれるときにメモリを あります 出てくるダークサイドの回避という一面も という目的もありますが : 思わぬところで 割りを明解に分けることによる理解の促進 外のものは class とします。 struct と class の役 みをメンバとして持つものは struct, それ以 として扱っていきます。つま叭データの ですが , この連載では st 「 uct と c ね ss を別物 トは public です。 ルトが p ⅱ vate なのに対し st 「 uct のデフォル トのスコープ制御だけです。 class のデフォ struct と class の違いは , わずかにデフォル 能なのです。 のように記述しましたが , 実は st 「 uct でも可 メンバ関数が持てるのは class だけであるか す。本文中では , , スコープの制御ができ ! ならば , st 「 uct もく拡張されている > からで と class の本質的な違いはありません。なぜ ~ にだけの話ですが , 実は C 十十では st 「 uct struct と class コラム f00 huge *P = new huge f00 [ 20000 ] ; / / Borland C + + 3.0 でのみ有効 12 : void main() { farfree(p) : } void operator delete(void far *P) { return farmal loc(n) ; } void far *operator new(size_t n) (char far * ) far 皿 110C ( 256 ) : } f00 ( ) { buffer ー 4 : public: char far *buf fer : 2 : class far f00 { 1 : #include く a110C. h > List class fa 「という記法の例 15 : 14 : 11 . 10 : 9 : 8 : 7 : 6 : 5 : 3 : リ The ◆ これは , デストラクタのほんの一例て、す。 メモリの確保・解放やファイルのオープン・ クローズなど , ペアになるような処理はい くらて、もあります。コンストラクタが派手 な話題を振りまく一方 , デストラクタの役 割は地味て、すが欠くことのて、きないものと いえます。いえ , 地味て、あるからこそ , っ い忘れそうになる後処理をきちんと行うた めにも , デストラクタの存在意義は大きい まとめ といえるて、しよう。 ログラムを開発する秘訣て、す。 ることが OS や CPU の機能を引き出したプ コンパイラの拡張仕様をうまく利用す す。 べて自動的にェクスポート関数になりま せることて、 , クラス内のメンバ関数がす ex pl icit functions exported ) を組み合わ これと -WDE オプション (Windows DLL 合は class export という書式を使います。 クラスを Windows の DLL て、定義する場 ます。 うメモリ確保の記法を組み合わせて使い ndC 十十 3.0 て、拡張された newhuge とい ェクトを使う場合は , far クラスと Borla て、は , また来月。 しましよう。 クラスとその周辺について見ていくこ まだまだ尽きません。これからしばらく , ます。しかし , クラスのさらなる奥深さは 機構のパワーを引き出すことは十分にて、き たものもありますが , これだけて、もクラス せそうて、すか ? おおまかな解説て、終始し どうて、す。クラス機構のパワーを引き出