List - みる会図書館


検索対象: 月刊 C MAGAZINE 1990年9月号
57件見つかりました。

1. 月刊 C MAGAZINE 1990年9月号

特・集コイラ てみたところ , 違っているのはループの部のページフレームやビデオ RAM など , 自分 イズがよく効いている。 また , 創刊号と同じ生成コード解析も実分 (List 9 ) だけて、あった。式の計算過程はまのデータセグメント以外て、アクセスする必 要のあるセグメントは通常限られており , ったく同一て、ある。 施した。カッコの解き方はなんとなく Ver. based ポインタが効率的に使える場面はかな 5.1 と似たものがあるが , レジスタの使い方 り多そうて、ある。オプティマイザはかなり と , 計算順序 ( Fig. 2 ) はまったく変わってし 賢くなっており , 驚異的だ。とにかく , 8086 まった。 0 十 1 ) や ( i 十 2 ) を求めるために LEA 用としては行き着くところまて、行き着いた 命令を使っているのがおもしろい。これも 新たに追加された based ポインタはちょっ印象を受けるコンパイラて、ある。 上記のべンチマークテストと同じように とややこしいが , なかなかおもしろい。 EMS Ox(List 8 ) と一 Ozax て、の生成コードを比較し ー Ox で生成したコードの解析 ( c6x. uas) ライプラリの使用例 ( base ⅱ st. c) さいごに LlSt LlSt 1 : #include く stdiO. h 〉 2 : #include く malloc. h> 3 : 4 : —segment listl,list2; 5 : 6 : struct cell-st { struct cell-st —based((-segment) self) *next; char —based( (—segment)—self) *data; 8 : 10 : 11 : struct cell—st based(listl) *headl, 12 : 13 : char dataC128] ; 14 : 15 : main() 16 : ( 17 : 19 : 20 : 21 : 22 : 23 : 24 : 25 : 26 : 28 : 29 : 30 : 32 : 33 : 34 : } 14 りム 0 4 6 1 亠 十 十 0 + レ + レ 0 1 人 00 6 ー 8 0 1- ・【 0 叮ー 0 つ 4 6 9 0 っ′ 0 叮ー 0 りな 00 ロ 0 ー 9 0 00 4 - ト 0 6 8 9 + 》りムり 0 つり 0 りなのっっっ 0 っ 0 れ 0 00 っ 0 っ 0 -4 4 4 4 4 4 -4 に 0 0 【 0 0 戸 0 ′ 0 6 6 6 6 6 6 6 6 叮ーー叮ーー「ーー叮ー 00 っ 0 -4 00 4 0 6 叮ー 8 9 0 1 ム 0 、↓ 1 よ、 1 0 ; BX ← a based(Iist2) *head2; : & a [ 11 ] —bheapseg(1024 * 48 ) ; listl —bheapseg(1024 * 48 ) : list2 / * read dataC] * / / * add cell to listl * / struct cell st —based(listl) *tmp; bmalloc(listl,sizeof(struct cell—st)); tmp bmalloc(listl,strlen(data) + 1); tmp->data fstrcpy( (char far *)tmp->data, (char far *)data) ; tmp->next ニ headl : headl tmp ; 十 * つ十 1 よっな ′、 1 0 ・ 1 ・ / * and so on * / ; SI ← 2 * ( TI + 1 ) ; AX ← TI : tmp3 ← J ド 2 ; TIA2 + 2 * ( TI + 1 ) ー J ド 2 ー Ozax で生成したループ部分 ( c6zax. uas) ループの部分 ( ー 0zax ) 100P 0028 SUB AX, AX 002A MOV BX, 01C0 002D MOV CX, 000A 0030 MOV DI, BX 0032 PUSH DS 0033 POP ES 0034 REPZ 0035 STOSW LlSt 特集米国コンバイラ事情 63

2. 月刊 C MAGAZINE 1990年9月号

米国 特・集コーイラ 事ー旧 らないときには有効て、ある。関数の引数に スて、きる点にある。あるセグメントを集中 のようにしてセグメント部が bs, オフセッ based ポインタを用いれば , メモリ容量だけ 的にアクセスするとき , たとえばビデオ RAM ト部が cp のメモリに '*0' を書き込める。 て、なく , 速度の点て、も有利になる。 のあるセグメントや , なんらかの I / O がマッ based ポインタのメリットは , そのサイズ ヒ。ングされているセグメント , ノヾッフアに sed ポインタ用の が near* インタと同じ 2 バイトて、あるにもか 使っているセグメントなどに , 複数のポイ ライプラリ関数 かわらず , far ポインタと同じ空間をアクセ ンタを使って複雑な処理を行わなければな MS-C Ver. 6.0 には , 上記のような based コード実例 (fastcall. c) ポインタの特長を生かすライプラリ関数が 追加された。 bheapseg, bfreeseg, bm alloc, bfree などの based ヒープメモリを 扱う関数て、ある。これは中規模のリストを 複数扱う場合 ( ひとつのリストは 64K バイト 以内だが , リスト全体て、は 64K バイトを越え てしまうような場合 ) などに便利て、ある。 れらのライプラリの使用例は List 7 に示した。 bheapseg て、ヒープ用のセグメントを得て , bma Ⅱ oc て、そのセグメント内のヒープメモリ を得ている。 List 7 て、は List 1,List 2 用に 48 K バイトのヒープメモリセグメントを確保し ている。リストへのアクセスは List 1 , List 2 をベースとして宣言したポインタ変数を用 いることて、簡単に行える。ここには List 1 に セルを追加するコードしか書かれていない が , List 2 に追加するコードもまったく同様 に書ける。 List cdecl ccc(int a, int b, int c, int d, int e, int f, int printf( ” %d Xd Xd Xd Xd Xd Xd}n ” ,a, b, c, d, e, f, g) ; ′ー、十し 14 りムれ 0 -4 - -0 6 ロー 8 9 0 ・ - ↓りムっ 0 4 ・戸 0 1 よ 1 ー一 1 よ 1 上 1 ー宀 11 fastcall fast(int a, int b, int c,int d, int e, int f, int g) printf("Xd Xd Xd Xd Xd Xd Xd*n ” , a, b, c,d, e, f, g) ; LiSt int 25h を使ったルーチン例 ( physread. c) 1 : physread(int drive, int sector, int numsec, char far *dta) _asm { 3 : 4 : push S 1 5 : push d i 6 : push 7 : push mov al,drive 9 : mov CX, numsec 10 : mov dX, sector 11 : lds bx, dta 12 : int 25h 13 : mov ax, 0 14 : JTIC noerr 15 : dec ax 16 : noerr: POP 17 : pop ds 18 : pop bp pop d i 20 : POP S 1 22 : } 23 : 24 : char buf [ 4096 ] ; 25 : 26 : main() 27 : { 28 : int i; 29 : physread(), 1 , 2 , (char far *)buf) ; 30 : for (i=0; i く 4096 : i + + ) printf("X02x 32 : 33 : } べンチマークテスト 本誌創刊号 C89 年 10 月号 ) と同一のべンチ マークテストを MS-C Ver. 6.0 についても 行った (Table 3 ) 。ただし , PC ー 9801 用の MS -C Ver. 6.0 はまだリリースされていないた め , テスト用のハードウェアには AX パソコ ンを用いた。テストは , 最大限の最適化 ( ー (x) と , それ以上積極的な最適化 ( —0zax) の 2 とおりを実施した。さらに MS-C Ver. 5.1 との比較のため , Ver. 5.1 についても AX パ ソコンて、再測定した。 今回のテストに用いたマシンは , SONY の Quarter L(PCX-300)0 CPU は 16MHz の 386SX , メモリは IM バイトて、ある。コンパ 特集米国コンバイラ事情 61

3. 月刊 C MAGAZINE 1990年9月号

の行を 0 に変えてアセンプルしてください 水平線の高速化については , PC98 の VR AM の 1 バイトが横 8 ヒ。クセルに対応 ( MSB が 左 , LSB が右 ) しているのて , 水平に線を引 くときだけは例外的に高速に引くことがて きるのて、す ( VRAM がこんな構造て、はないほ うが , このような場合は楽なんて、すが・・・ 基本的には C て、表すと次のようなルーチン (List 1 ) て、処理しています。見やすさを優先 したため最適化の類は施していません。 実際は , GVRAM に対するバイトアクセス をワードアクセスにし , スヒ。ードアップを 図った結果 , 多少複雑になっています。も もちろんそれに応じて List 1 の table [ ] に あたるビットシフトテープルも変更してい ます。 cline. asm につけ加えた長方形描画関 数 gbox( ) は , これを少し改良すると簡単に て、きます。 基本的には水平ラインを縦の長さだけ繰 り返して引くことになります。強いて最適 化のポイントを挙げれば , 縦のアドレスは 1 本水平線を引くごとに 80 バイトずつずれて いくのて , そのたびごとに計算し直さない ことと , 両端のマスク ( List 1 の rmask,lmask にあたるもの ) も可能ならレジスタに保存し ておくことくらいてしようか。 C て書くと List 2 のようになります。大筋 は List 1 の h ⅱ ne ( ) と同じてすが , 線を繰り 返し描かねばならないのて、少しだけ変数の 保存に気を配る必要があります。アセンプ ラて高速にやろうと思うと , レジスタをフ ルに活用しなければなりません。 far'* インタ BpIane の使い方が List 1 と少 し異なりますが , List 2 のほうがアセンプラ てやっていることに近いと思います。 テストルーチンは青い蚊取線香 ( のような もの ) を描くものて、す。コンパイルしてみて GBOX equ ください 1 23 : / * draw * / 38 : } 46 : } 12 : { LiSt 1 22 : 24 : 26 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 36 : 39 : 42 : 43 : 44 : List 2 6 : 8 : 13 : 14 : 15. 16 : 17 : 20 : 22 : 23 : 24 : 25. 26 : 28 : 29 : 30 : 31 : 32 : 33 : if ( xl 〉 639 Ⅱ x2 くの return; lmask ニ tableC()1 % 8 ) ] : -tableC x2 % 8 + 1 ] ; rmask x2 / ニ 8 ; = x2-x1 : 1 if(i== の { rmask & = lmask; *(Bplane + Y*80 + (l) ト rmask; } else { *(Bplane + Y*80 + (l) ト lmask; *(BpIane + Y*80 + (l) = 255 : *(BpIane + Y*80 + (l) ト rmask; / * 左ピットマスク * / / * 右ビットマスク * / / * テストルーチン * / 40 : main() int i; for ( i = 0 ; i く 320 : i + + ) { 2 : #include く stdlib. h> 1 : #include く math. h> hline ( 320 ー i , i , 320 + i ) ; draw box (subset version) * / 3 : / * box. c 4 : void box(int xl, int yl, int x2, int y2); 5 : / * B-plane で ( xl , yl ) と ( x2 , y2 ) を対角線とする長方形を描く 7 : char far *Bp1ane; 9 : char table ロ = ( 255 , 127 , 63 , 31 , 15 , 7 , 3 , 1 , の : 11 : void box(int xl, int YI, int x2, int Y2) if ( xl 〉 639 Ⅱ x2 くの return; if ( x2 〉 639 ) x2 = 639 ; if()l くの xl = 0 : tmp ; x2 xl = x2; int tmp = xl; if(x1>x2){ ・ / * clipping & normalizing for x * / if ( yl 〉 399 Ⅱ y2 くの return; if ( y2 〉 399 ) y2= 399 ; if()l くの yl = 0 ; tmp; Y2 ; int tmp=yl ; if(y1>y2)( ・ / * clipping & normalizing for y * / char lmask, rmask; int i; 124 CMAGAZINE 1990 9

4. 月刊 C MAGAZINE 1990年9月号

C の道具箱 応甬 c List 5 0 int locatec(x, [ 引数 ] int x, y ; LO 0 - ト 0 exit( の : x, y は , 表示位置を示す X 座標および Y 座 標て、ある。 [ 戻り値 ] Fig. 4 特殊キーの対応 D7 D6 x および y の値が画面の範囲外にある場合 に , 1 を返す。 SHIFT CAPS カナ G R P H CTRL 0 0 0 [ 機能 ] カーソルを座標 ( x , y ) の位置に移動する。 この機能は , 工スケープシーケンスに関 するヘッダファイルをインクルードするこ とによっても実現てきる。しかしへッダフ ァイルが大きくなりすぎた場合などには , このような関数をライプラリに含めて使用 するほうがよい場合がある。 [ 使用例 ] List 7 および Fig. 6 を参照。 midins 関数 (List 8 midins. c 参照 ) 文字列の挿入 [ 書式 ] #include <string. h> Fig. 5 test2. exe の実行画面 B>TEST32 FI キーが押されました FI ~ キーが押ざれました F6 キーが押されました F6 キーが押されました BS キーが押されました 右矢印キーが押されました int midins(ss, iS, a) [ 引数 ] char *SS : char * iS ; int a ; * is には , 挿入する文字列を格納する変数 を指定する。 *ss には , 挿入先の文字列を指定する。 a には , 何文字目に挿入するかを指定す トの各ビットに対応している。 [ 使用例 ] List 5 および Fig. 5 を参照。 locatec 関数 [ 機能 ] (List 6 locatec. c 参照 ) 表示位置の指定 ファンクションキー , キー , 矢印 キー , ーキーといったプログラムの [ 書式 ] 制御に使用するキーの押し下げ状態を取得 #include <stdio. h> する。 [ 戻り値 ] 正常終了の場合 0 を返す。 応用 C 言語 91

5. 月刊 C MAGAZINE 1990年9月号

まー ~ 、す 面 画 の 最 4 果 4 は判 字、文 t-f) 文 ( 」る v-, 在のす , ⅲ 7 > 初 ~ 入、「沼 Fig. 6 test3. exe の実行画面 0 C U CA SU VOID N\NL ー N S R E P 日 > TEST33 ト ~ ト一トト ス、ス〔スス テ第テテ〈テ 1- 2 一ー 3 一 4 [ 機能 ] 文字列 ss の a 番目から文字列 is を挿入す る。ただし , 挿入により長くなった部分は 切り捨てられる。 [ 使用例 ] List 9 および Fig. 7 を参照 midtorup 関数 (List 10 midtorup. c 参照 ) 文字列の削除 locatec. C List 6 1 : #if !defined(NOT い B) #include く stdio. h> 2 : 3 : #endif 4 : 5 : locatec (), Y) 6 : i nt X, y : if(x く 0 Ⅱ x > 80 Ⅱ y く 0 Ⅱ Y > 25 ) 8 : return(l) : 9 : printf("%xlb[") : putchar(y/10 + ・ 0 ・ ) : putchar(Y%10 + ,0 ・ ) : putchar( ・ : 13 : putchar(x/10 + ・0,) ; 14 : putchar(xX10 + ・ (,) : 15 : putchar( ・ H ・ ) : [ 書式 ] #include <string. h> int midtorup(ss,a,b) [ 引数 ] char *SS : int a,b : test3. c List 7 2 : #include く stdio. h 〉 3 : 4 : void main() Iocatec(25,5 );printf(" テストー 6 : Iocatec(25,1 の ;printf(" テスト - 7 : Iocatec(25,15);printf( ”テスト - 8 : Iocatec(25, 2 の :printf(" テスト - 9 : ex i t ( の : -1 ワ】 3 4 こは , 削除の対象となる文字列を指 * SS ( 定する。 a には , 何文字目から削除するかを指定す 何文字分削除するかを指定する。 b には , [ 使用例 ] List 11 および Fig. 8 を参照。 [ 戻り値 ] 正常終了の場合 0 を返す。 ou 廿 orm 関数 (List 12 ou 廿 orm. c 参照 ) 特定の書式でメモリへ書き込み [ 機能 ] [ 書式 ] 文字列 ss の a 番目から b 文字分の文字を削 #include <string. h> 除する。ただし , 削除により短くなった部 分はスペースて埋める。 92 CMAGAZINE 1990 9 [ 引数 ] cha 「 *ds : char * SS ; * ss にはオリジナルの文字列を代入する。 * ds には , 特定の書式に書き直された文 字列が格納される。 int outform(ds, ss, stype)

6. 月刊 C MAGAZINE 1990年9月号

学生番号 x , 課目番号 y の成績を a にする 14 : } List 6 1 : 8 : 7 : 6 : 5 : 4 : 3 : 1 : 13 : 12 : 10 : 9 : 7 : 4 : 3 : VOid add(int x, int y, short a) p¯>seiseki p->kamoku = &kamoku [y] : p->gakusei = &gakusei [x] : kamoku[y]. klink p->klink = kamoku[y]. klink; P , gakusei [x] . gl ink p->glink = gakusei[x]. glink; error ( " メモリが足りませんつ : = malloc(sizeof(struct SEISEKI))) if ((p struct SEISEKI *p; = NU しい 学生 x の課目 y の成績を得る ( 履習していないときは一 1 を返す ) struct SEISEKI *p; VOid get_seiseki(int x, int y) List 7 for (p ー gakusei[x]. glink; P ! = NU しし: = &kamoku [y] ) (p->kamoku return (p—>seisek i ) : ー 1 : return i f P = p->glink) ある課目 ( 課目番号 x ) を履修している学生の名前と成績をプリントする List 8 1 : VOid print-gakusei (int x) 3 : 4 : 5 : 6 : struct SEISEKI *p; for (p ー kamoku[x]. klink; p ! = NU しし : p = p->klink) printf("Xs Xd*n" p—>gakusei—>name, くと , この課目の成績レコードを順にたど ることがて、きます。 また , このほかに成績レコードがどの学 生 , 課目に所属しているかを示すポインタ をもたせなければなりません。このポイン タがないと , 配列 gakusei から g ⅱ nk をたどっ て , ある成績レコードにたどりついたとき , その成績レコードがどの課目のものなのか を知ることがて、きません。学生を表す ( 配列 gakusei への ) ポインタをメンノ *gakusei に 課目を表す ( 配列 kamoku への ) ポインタをメ ンノヾ kamoku にセットします。 結局 , 成績レコードは , 5 つのメンバをも っていることなります。 Fig. 6 て、は , 成績レ コードは , 5 つに区切られた横長の長方形と して表されていますが , 左から順に , メン ノ *seiseki, gakusei, kamoku, klink, glink 70 CMAGAZINE 19 9 になります p->seiseki), るべきリストにつなぎこみます。まず , 最 List 6 は , 成績レコードを作成して , しか す。 れもどの課目も履修していない状態にしま kamoku の全要素に NULL をセットして , だ ます。 List 5 の初期化て、は , 配列 gakusei, 課目の名前を表すメンバ name が含まれてい kusei, kamoku には , それぞれ学生の名前 , 定義は List 4 のようになります。配列 ga ざっと見てみましよう。まず , データ型の このデータ構造を操作する関数について 2 が 35 点と成績がふるいません。 績は 72 点て、す。学生 2 は課目 1 が 52 点 , 課目 また , 学生 1 は課目 0 のみを履修し , その成 2 が 83 点て、す。課目 1 は履修していません。 Fig. 6 て、は , 学生 0 は , 課目 0 が 90 点 , 課目 初に , 成績レコードを割り当てます。そし ドがあるかどうかを検索します。みつから をたどりながら , 課目番号が y の成績レコー 調べます。これは , 配列 gakusei から , glink List 7 は , 学生番号と課目番号から成績を て、す。 は , さらにリストの数が増えても同じこと のふたっ ) 繰り返すことになります。これ 入をリストの数だけ ( この場合は , g ⅱ nk , k ⅱ nk ぎこみは , 基本的には , 連結リストへの挿 します。このように , 多重リストへのつな 績をメンバ seiseki にセットして処理が完了 ku へのポインタをセットします。最後に成 ノ *gakusei, kamoku に配列 gakusei, kamo て , glink, k ⅱ nk のつなぎこみをして , メン 次に多重リストを使う場合について考え す。 した計算量になります。つまり , O (A) て、 しなければならないのて、 , 学生の数に比例 ようか ? これは , 配列 seiseki をスキャン だけて、すみます。操作 c についてはどうて、し seisekiCxJ Cy] a は , a と b は明らかに O ( 1 ) て、す。たとえば , 操作 データ構造として配列を使う場合 , 操作 と , C, D はかなり小さいことに留意しまし となります。ここて、 , 一般に A, B に比べる 定て、は , A = 2000 , B = 400 , C = 10 , D = 50 たりの平均学生数を D とします。先ほどの想 生 1 人当たりの平均履修課目数を C , 1 課目当 ましよう。学生の数を A, 課目の数を B, 学 ぶことにします ) の操作の計算量を求めてみ こて、 ,List 6 ~ 8 ( それぞれ操作 a ~ c と呼 多重リスト構造の計算量 名と成績をプリントします。 レコードが指している学生レコードの学生 列 kamoku から , klink をたどりながら , 成績 の学生の名前と成績をプリントします。配 List 8 は , ある課目を履修しているすべて なければ , ー 1 を返します。

7. 月刊 C MAGAZINE 1990年9月号

もちろん無保証てすが・・ ださい 「 GNU CC は確かにすごいコードを出す 本来なら DIFF 式カ , 適切なのてすが , md が , short int 演算の遅いコードを出す」と , は変更点が多すぎて要点だけしか出せませ このような宣言が GNU CC て、は許されて 私に代わって X68000 の LH (LHarc) をサポー んてした。 います。内部的には builtin a Ⅱ oca ( これも トしている「やーさん」がいっていたのて少 GNU CC の拡張機能て、 , スコープが関数内 し調べてみました 0List 8 はポインタを使用 割り込み処理関数 部だけの ma Ⅱ oc と同じと考えられ , 実際の した演算てすが , GNU CC は ? ? ? の部分て納 領域て、はスタック上にとられます。 malloc 得て、きないコードを出力しています。さら を GNU CCC と異なるのは free する必要がないことて , ス に調べていくと , バグらしきものも発見し コープを出ると消滅します ) とほとんど同じ ました。 List 9 のような , コードが正しく分 GNU CC を改造して , 割り込み処理が記 だと考えられます。実際の内部処理もほば 岐て、きないものになっています。 List 8 の Test 述てきるようにしました。毎月 , 役に立ち 同一て、す。 1—Test 4 て、は , とくに動作に支障はありま そうもない ( ? ) List ばかりなのて , 今回は全 せんが , List 9 の Test 5 は致命的て、す。どう 最近見つけた ソースと実行形式をディスクに収録してい やら , 680 ? 0 用の md ファイルに誤りがあるよ ただきました ( これが役に立っとはいえませ うて、す。 List 10 ( 付録ディスク参照 ) に修正 GNU CC の疑問点 んが , これまてに収録されたプログラム中 該当部分を挙げておきます。 GNU CC をコ の LH 以外て、 , おそらく X68000 てしか実行て ンパイルて、きる環境にある方は修正してく foo(moji) ・ List static inline int def-char(int code ,char *pat) asm ("d0") ; register int 1 OC S code-n asm ("dl") : reg ister int register char *pat-ptr asm ("al") : asm ("trap # 15 " "=d"(iocs) "d"(iocs = 0xf), "a" (pat-ptr = pat) , "d" (code-n ・生成されたコード . text . even . g10b1 -test link a6 , # 0 moveq. I # 15 , d0 lea _buf,al move. 1 -kanj i, dl * APP ON (APP) trap # 15 * APP OFF (NO_APP) tst. 1 d0 beq ? 4 JSr _error un I k a6 rts test: / * 終了コード * / / * iocs call no * / / * buffer address * / ニ code)) : / * kanji code return iocs; extern char buf ロ : extern int kanj i : VO i d test ( ) if (def-char (kanji, buf)) error ( ) : beq ? 6 JSr _error addq. w # 4 , a3 addq. 1 # 1 , d6 c 叩 . 1 d6,d7 bgt ? 9 movem. 1 ー 24 (a6) , d3/d4/d5/d6/d7/a3 un 1 k a6 rts 136 CMAGAZINE 1990 9

8. 月刊 C MAGAZINE 1990年9月号

文字配列の初期化 して , 確認しています。 これに対して , 以下のように宣言したと 割り当てられるのてす。 いるわけてす。つまりメモリ上に「静的」に 呼び出されたときには , 前の値を保持して ドレスは不変て、す。そしてこの関数が再度 ませんが ) , 文字配列 a が格納されているア 合は main 関数なのてそのようなことはて、き れ以後この関数を何回呼び出してもにの場 れ , 固定アドレスが割り当てられます。そ 列 a は呼び出されたときに一度だけ初期化さ 場合は main 関数 ) が呼び出されると , 文字配 り当てられます。この宣言を含む関数にの と宣言するとコンパイル時にアドレスが割 ” Hello, World!! ” static char a[] に説明してみましよう。 List 3 のように ねて , 「静的」と「動的」の違いについて簡単 もうご存じかもしれませんが , 復習を兼 いたため , static< 宣言しました。 け多くのコンパイラ上ての動作を念頭に置 ります (M S ー C Ver. 5.1 など ) 。てきるだ ないと配列の初期化がてきない処理系があ のに限られていました。現在ぞも static にし しかし , K & R ては配列の初期化は静的なも ざわざ static て宣言する必要はありません。 C ては配列の動的初期化が可能なため , わ 字配列を宣言したのは理由があります 0ANSI また横道にそれますが , List 3 て静的に文 します。 大きさを 15 と計算し , 配列 a [ 15 ] を宣言し れたときにコンパイラは ' \ 0 ' を含めて配列の と消滅します。まず , この関数が呼び出さ れたときに生成され , その関数が終了する これは自動変数なのて , 関数が呼び出さ 'Hello, World!!" char a [ ] ます。そしてその配列に , a [ 15 ] a [ 14 ] a [ 0 ] CMAGAZINE 19 9 のようなイメージて , 「動的」に値が代入さ 112 れ , 初期化されます。この場合 , 関数が呼 び出されるたびに文字配列 a は生成され初期 化されます。関数呼び出しが終わるとこの 配列 a も消滅します。 配列とポインタの関係② さて , 本題に戻りましよう。 List 2 の 20 行 目からの関数 pst 「 cpy を見てください。この 関数は文字列操作を純粋に配列として扱っ ています。この関数が正常に動作する理由 は , 今まて、の説明により簡単にわかるかと 思います。 また , 関数 pstrcpy には , 配列の先頭ポイ ンタを渡せばよいのて , 実引数は a , b とな っていますね ( 12 行目 ) 。 次に , List 4 の 20 行目からの関数 pst 「 cpy こて、は , 引数がポイン を見てください タて、あることを前面に打ち出してプログラ ムを組んています。文字配列の先頭ポイン タを受け取ってポインタを進めながらコヒ。 ーしています。このような簡潔な書き方は C 言語て、非常によく使われ , 慣れてくれば 便利なものて、す。最初は , 文字列のコピーを行う関数 pst 「 cpy ( その 2 ) List 4 VOid pstrcpy( char *a, char *b ) ; 1 : #include く stdio. h> 2 : 3 : 4 : 5 : 6 : 9 : 12 : 13 : 14 : 20 : 22 : 23 : 7 : VO i d ma i n ( vo i d ) Char *a ” Hello, cha r b [ 80 ] : pstrcpy( a, b ) : printf("a : %sYn ” printf()b : %sYn", b ) : Wo d. ” * a 十十 ) while ( * b + + = VOid pstrcpy( char *a, char *b ) 24 : } 1 : 26 : } List 5 文字列のコピーを行う関数 pst 「 c ロ Y ( その 3 ) 2 : 3 : 4 : 5 : 6 : 9 : 20 : 22 : 23 : 24 : 25 : #include く stdio. h> VOid pstrcpy( char *a, char *b ) : 7 : void main( void ) ”日 e Ⅱ 0 , Char *a char b[ 80 ] : pstrcpy( a, b ) : printf("a printf("b World. ” VOid pstrcpy( char *a, char *b ) i nt i :

9. 月刊 C MAGAZINE 1990年9月号

「 0 凵はオペランドとともにデータレジスタ とをコンパイラに指示します。一見正しく たいしておもしろくない例てすが , MOVE て、す。制約文字はヾ d クて、 OK て、す。とくに 見える List 5 も誤った結果となります。 は変数 f00 を返す関数てす。 〃の後の 返す値を dO に割り当て , 最短のコードに 誤りはないように見えますし , コンパイラ 〃という制約文字は , 非常に重要な しているのは gcc の最適化てす。 gcc ては asm も何のメッセージも出しません。ところが 意味をもちます。この文字列は , そのアセ 文の式をも最適化の対象としています。 出力コードはリスト後半のようにア然とす ンプラコードが要求するアドレッシングモ るものになってしまいます。これは , 3 オペ 実際の ードを制御します。この制約文字には機種 ランド演算を 2 オペランドとして asm 文て扱 依存性があるのて、 , X68000 以外の gcc を使う った場合に多発するミスて、す。「 0 凵命令を コーディング例 場合は各ソースファイルのマシンディスク 次のように考え , asm 文てコーディングしま リプションファイルを参照してください す。 asm 文のインブットオペランド , アウトプ X68000 の gcc ては以下の 3 つを覚えておけ asm ( " 「 0 凵 % 2 , % 0 " ットオペランドは実際のオペレーションコ ば十分て、しよう。 (0P0),"d" ( 0P1 ) ) : ードに出現する必要はありません。 X68000 g 〃 68000 て、許されるアドレッシング の iocs コール $ f 外字登録を例に実際にコーデ モードのほとんどが適応されます 0P0 「 0 凵 0P1 0P2 イングしたものが List 6 てす。 〃データレジスタを使います 実際の命令て、は 0P2 は 0P0 と同じ場所を占め 関数内部のレジスタ変数は , 直接レジス a 〃アドレスレジスタを使います ると考えます。この同じ場所を占める表現 タを指定しています。 qtrap" 命令自体は , がヾ数字〃てす。 List 4 の " 0 " (x) は output 具体的な例を見てみましよう。 List 3 は 入力も出力もしませんが , あたかも複数入 operand の "=d"(x) と同じ場所を占めるこ asm 文に慣れていないと面食らう例て、す。 List i nt f00 : int move(void) ・生成されたコード . text . even . g10bl move move ・ * APP ON (APP) f00 , d0 move. 1 * APP OFF (NO_APP) rts 0 ・ー CO O Li st int rol(int x,int y) return x; ・生成されたコード . text . even . g10b1 -rol ro I : move. 1 8(sp),d1 * APP ON (APP) rol.l d1,d0 * APP OFF (NO_APP) rts 134 CMAGAZINE 19 9

10. 月刊 C MAGAZINE 1990年9月号

C の道具箱 stype には , 書式指定用の整数を指定す る。この書式は , input. h において以下のよ うに定義されている。 [ 戻り値 ] 正常終了の場合 0 を返す。 midins. C List 8 1 : #if !defined(NOT い B) 2 : #include く string. h> 3 : #endif 4 : 5 : midins(ss, iS,a) 6 : Char *SS 7 : Char * i S : 8 : i nt a 10 : i nt n 11 : char sIeft[256]; 12 : char sright[256] : n=strlen(ss) if( 0 く a & & a く = n ) { mid(sleft ,ss,l,a-l); 15 : mid(sright,ss,a,n-a + 1): 17 : strcat(sleft, (s) : strcat(sleft, sright) : mid(ss,sleft,l,n) : 20 : return( の : 22 : } 23 : [ 機能 ] 文字列 ss の中の空白を取り除き , 再び ss に格納する。 spctoru 関数 (List 13 spctoru. c 参照 ) 空白の削除 [ 書式 ] #include く string. h> int spctoru(ss) [ 引数 ] char *SS ; test4. c List 9 2 : #include く stdio. h> 3 : #include く string. h> 4 : 5 : void main() 7 : char mojil [ 256 ] ; 8 : char 田 oji2 [ 256 ] : strcpy ( 田 Oj i 1 に A A A A A A A A A A A A A A つ : 9 : strcpy(moji2, "XY Z つ : printf(" 最初の文字は Xs です YnYn", mojil) : printf ( " 挿入する文字は 12 : Xs です YnYn", moji2) : midins(mojil,moji2,7); 14 : printf("midins の結果、最初の文字は % s になりました \ n " , mojil ) : ex i t ( の : 17 : 空白を削除する文字列を指定 * ss には , する。 [ 戻り値 ] 正常終了の場合 0 を返す。 [ 機能 ] 文字列 ss の中の空白を取り除き , 再び ss に格納する。 tolowers 関数 (List 14 tolowers. ce 照 ) 文字列の中の英大文字を英小 文字に変換 midtorup. c List 10 1 : #if !defined(NOT い B) 2 : #include く string. h> 3 : #endif 4 : 5 : midtorup(ss, a, b) 6 : Char *SS : 7 : i nt a, b 9 : i nt n : 10 : char 引 eft [ 256 ] : 11 : char sright[256]; 12 : char spacee[256] : n=strlen(ss) : strcpy(spacee. strcpy(sleft , strcpy(sright, " i f ( ( 0 く a & & a く n) & & ( 0 く b & & mid(sleft ,ss,l,a-l); nid(sright, ss, a + b,n-a-b + 1) : 20 : strcat(sleft, sright) : strncat(sleft, spacee. b) : 22 : [ 書式 ] #include <string. h> #include <ctype. h> int tolowe 「 s(ss) [ 引数 ] char *SS : 英大文字を含む文字列を指定 * ss には , する。 応用 c 言語 93