コンパイラ - みる会図書館


検索対象: 月刊 C MAGAZINE 1991年4月号
75件見つかりました。

1. 月刊 C MAGAZINE 1991年4月号

初級 c プログラマに贈る最斤 うことをやっている人が多かった。 また現在の C 言語て、は , たとえば atol ( ) ( こ の標準関数がわからない方は C 言語のライプ ラリリファレンスを参照してください ) など という int 以外の戻り値を返す標準関数を使 long a ; main( ) long atOl( ) : うときには , a atOl(.. というようにあらかじめ戻り値の型を定義 この定義は標準ライ しておく必要がある。 ことに気をつけるべきてある。 K & R の話て、 は「例外」としてついているものだ , という う機能をもつコンパイラは , その機能が実 本当は「未定義なシンポルが使える」とい て、ある。 機能がコンノヾイラにオマケて、ついているの 値はすべて int て、あると解釈される , という る。つまり未定義な関数を使うとその戻り とんて、もない目に合う , というよい例て、あ じゃない などとたかをくくっていると , を出してくれる。が , 警告て、あってエラー 最近のコンパイラて、は , この程度は警告 ビットが削られた値が入ってくることにな 最初の 1 行の定義を忘れると , a には頭の 16 ビットの符号つきということなのて、 , もし どて、は int は 16 ビットの符号つき , long は 32 在のパソコンの MS ー DOS 上のコンパイラな 理系て、あれば問題はまず出ないのだが , 現 勝手に解釈してしまう。 int が long と同じ処 atol( ) の戻り値は int て、あるとコンパイラが そしてこのあらかじめの定義を忘れると , 同じて、ある。 もちろん , 標準関数て、なくともやることは ヘッダを include しても , 同じことて、ある。 プラリ用へッダに定義してあるのて、 , その いえば , プライアン・カーニハンとデニス・ リッチーはその本の例題がそのまま動くよ うに彼らの C 言語コンパイラに例外をもうけ たのて、ある。もちろん , 本来ならば本のほ うて、きちんと説明するべきなのだが , それ がめんどうくさいのて、コンパイラのほうを 直した , という想像はあながち外れてはい ないだろうと思う。 K & R 両氏は権威て、はあるが神様て、はな い。つまりまちがえもするし , 感情だって ある人間て、ある。「 K&R 」にだっておかしな ところはある。もちろん , 彼らの業績はそ の「部分の違い」程度のものて、消えてしまう ようなちつばけなものて、はない というの もまた事実て、ある。 C 言語は決して数学的にきれいな言語て、は ない。 C 言語て、の言語仕様の数学的な美しさ というものは「つけたし」にすぎない。シス テムソフトウェアの記述言語として , 数学 的にはまるて、美しくない CPU の機械語とい う現実世界と , これまた数学としてはさら に美しくない人間の世界を結びつけること を第一の目的として書かれた言語て、ある。 美しくなくて当然だし , それて、いいのて、あ て、ある。 という動物的なカンがヒ。ンと働く部分なの 然にそのバグがありそうなところを避ける , ったところなどは , 経験を積んて、くると自 の「未定義シンポル」の扱いについて , とい らせておくべきて、あると思う。とくに前述 ということについて思いを巡 もしれない , のなのだから ) 信頼に値しない部分があるか らない開発環境」にだって ( 人間の作ったも ラやハードウェアなどの「信頼しなければな また , 私は「保険」といったが , コンパイ とて、ある。 ついても考えてみる必要がある , というこ として C 言語のコーディングスタイルなどに く「デバッグしやすいかどうか」という問題 心にすえると , 「好み」の問題としてて、はな 詰まるところ , デバッグという問題を中 私がほとんど無意識のうちに「 main ( ) 」を ソースコードの下に置く , ということにな ったのも , そういう「クセ」がついているか らなのだ。とくに「仕事」て、のプログラミン グの場合などは , コンパイラのバグなどて、 かなりたくさんの時間を費やしてしまうこ とも希て、はない だから「それ」に当たって , コンパイラメ ーカーに文句をいって「おれはこんなにデキ ルんだゾ」という普段は満たされない自己顕 示欲をここぞとばかりに満たそうとする輩 にはっきあっているヒマはない , という「仕 事のプロ」にとっては , こういった「保険」も 財産て、あるといえるだろう。事実 , 私はそ の「クセ」に恩恵を受けていると思う場面に よく出食わすのだ。 以下にほかの似たような私の「クセ」の例 を思いつくままに掲げてみよう。 ①いくつもネストする式のカッコは避け る ( せいぜい 4 個まで ) ②ループや条件判断などのネストはだい たい 3 個までとする ③演算子の優先順位を考える必要のある 式は書かない。優先順位が関わってき そうな場合は必ずカッコでくくるか , 演算の途中結果を入れておく変数を介 して計算を行う ④ if( ) などの中での比較演算で定数と変数 の比較などは , 定数を必す左辺に置く ⑤変数名 , 関数名などは長くても読むと わかるものにする ⑥コンバイラの通常のレベルでのワー ング ( 警告 ) メッセージは無視せす , ほ とんど出さないようにプログラムを修 正する。出たらきちんとっぷして , 出 ないようにしておく。またしかたなく 出るものについては「なぜ出るか」を把 握しておく コンパイラやハードウェアのバグに当た ることを楽しみにしている , というヒマの あるアマチュアの場合や , いくら仕事をな くしても 100 年は食っていける , という恵ま 特集初級 C プログラマに贈る最新デバッグ学入門 41

2. 月刊 C MAGAZINE 1991年4月号

more た文字列は単一の実体をもつようにするこ ては List 5 に類似している。ただし , 変数を の構造体 (struct) や共用体 (union) も ANSI C 割り付ける領域がスタックてあることが決 とも可能て、ある。ただし , これを実行して ては初期化て、きる。 K & R ( 1 版 ) の規定てはそ 定的な違いて、ある。次に初期化データとし いるコンパイラは少ない。文字列定数を変 れらは static て、ないと初期化てきなかった。 更するような「古い」プログラムをコンパイ て文字列 " hello , w 。 rld " を見た時点て , 定数 また , union は auto/static のいずれにせよ初 ルする場合を考えてのことかもしれない 領域に文字列 " he Ⅱ 0 , world " を ( ' \ 0 ' を付加 期化て、きなかった。残念ながら一部の「 ANSI 同様に , 文字列定数の実体を格納する領域 準拠」のコンパイラては auto 配列の初期化を して ) 格納するようにする。 は「定数領域」てはなく「 data 領域」としてい 関数 f 。。の内側ては , 文字列定数と同じサ 許していない。たとえば MS-C も Ver. 5.1 ま イズの文字配列領域をスタックの上に確保 るコンパイラも多い。またコンパイラによ てはこれを許していなかった。 MS-C Ver. し , b という名前をつける。そして関数 f00 っては , デフォルトては文字列定数を data 5.1 が ANSI 規格そのものだと考えていると に進入するたびに , 毎回定数領域から配列 領域に格納するが , なんらかのスイッチを 誤解してしまうのて、注意が必要てある。 b へと文字列の内容をプロック転送 ( 文字列 指定することて定数領域に格納てきるよう List 8 も , 動作結果はこれまてのプログラ のコビー ) するのてある。それから puts の呼 にしているものもある。 ムとまったく同じてある。その大きな違い び出し時に , b の値 , すなわち & b [ 0 ] を渡 は初期化のメカニズムにある。先に翻訳結 auto の文字配列 すのてある。 果を示しておこう (Fig. 4 ) 。 コンパイラは , 宣言 charb [ ] を見たと List 6 から static を取り去った List 9 が考 えられるが , これもコンパイル結果は List 6 さらに , List 5 から static を削除した List ころて , b を char の auto 配列だとしてスタッ が List 5 に等しいのと同様に , List 8 に等し 8 はどうなるかを考えてみよう。あらかじめ クの上に領域を確保するように準備する。 注意しておくが ,List 8 のように「 auto の配 そして , 配列のサイズの指定がないのて初 い List 5 , List 6 と List 7 , List 8 の違い 列を初期化て、きる」機能は ANSIC になって 期化されることを期待し , その初期化デー は , 前者の場合には , 配列が static に data 領 正式に定められた機能てある。ほかにも auto タのサイズに合わせるようにする。 域確保されるため初期化はコンパイル時に Fig. 4 List 8 の翻訳結果 一度だけ行われるのに対して , 後者の場合 定頁域 には , 配列は auto なのてスタックの上に確 保され , 関数 foo が呼び出されるたびにプロ ック転送によって初期化が行われる点てあ る。したがって , 関数 foo の内側て配列 b の 内容を変更した場合 , List 5 , List 6 ては , 次回の関数呼び出しては変更後の値をアク セスするのに対して , List 7 , List 8 ては , 次回の呼び出しの時点て再度初期化が行わ れるため変更の影響を受けない。これが両 者の違いてある。また , List 7 , - List 8 て は , 配列 b の領域は関数を抜け出した時点て 解放されてしまうために , 抜け出した時点 て配列 b の内容をアクセスすることは誤りて ある。たとえば関数 f00 を修正して配列 b の アドレスを返したりするためには , それは static て、なければならない 別の観点から説明をすると , List 8 , List 9 は , 実際の動作としては List 10 に非常に近 いということてある。 スタック領域 ー b: 'h' ー puts puts の呼び出しに対して、 配列 b 窈直 , すなわち先 豆腰素のアドレスを渡す 関 00 の内側て定数領 域からスタック領域へと、 文字列定数全体をコピー ℃ ' する 'VO' ANSI C more 105

3. 月刊 C MAGAZINE 1991年4月号

Fig. 1 LSI Cー86 で List 1 をコンバイルしたときのエラーメッセージ A> lcc listl . c cpp -iÆ*LSI*lNCLUDE* -dLSLC ー 0 1. $ $ $ listl. c Fig. 2 和を求めるプログラム # include く stdio. h> int main (void) printf("%d", 5 十 3 ) ; 「 eturn ( 0 ) ; 明解 AWC 言ロロ おまじない おまじない 入門講座 cf -chcyt 1. $ $ $ 2. $ $ $ 3. $ $ $ listl. c 1 : syntax er 「 0 「 near ' 5 ' い。付録ディスクの LSI C ー 86 て、コンパイル する場合以下のように行います。 A>IccIist1. c Turbo C ( 十十 ) や QuickC などの処理系て あれば , 割り当てられているファンクショ ンキーを押すだけてコンパイルて、きます。 各コンパイラの使い方については , お手元 の各マニュアルを参照してください 正しくコンパイルてきましたか ? Fig. 1 のようにエラーが出たはずてす。プログラ ミング言語は電卓とは違います。 5 十 3 のよ うなプログラム ( ? ) はまちがいて , コンパイ ラは受け付けません。 正しいプログラムは Fig. 2 のようになりま す。なんだかよくわかりませんね。電卓な らば , 5 十 3 と打つだけて計算結果を勝手に 表示してくれますが , プログラムて表示を 行いたいときは , 「表示せよ」という指示を コンピュータに与えなければなりません。 LSI C ー 86 の使い方と Vz 工テイタ LSIC ー 86 の使用法を書いたドキュメントフ ァイルを付録ディスクのく BOHYOH > ディレ クトリに格納しています。詳しくはそちら をご覧ください。 また vz 工デイタをご使用の方のために コンバイル・実行などがメニューから選択 できるマクロも付録ディスクに格納してい ます。 vz 上でメニューを選択するだけでコ ンバイルや実行ができるようになります ( L だけでなく Turbo, MS, Lattice, power など の処理系や他の言語にも対応しています ) 。 「表示せよ」を実行 ( 指示 ) するのが ,printf と いう関数てす。 printf 関数を使って 5 十 3 の値 を表示させるには , printf("%d", 5 十 3 ) ; となります。ここて % d は「出力を 10 進数て 行え』という書式を指定する意味をもちま す。 Fig. 2 の printf("%d", 5 十 3 ) ; の前後の 部分は , とりあえず「おまじない」と覚えて しばらくのあいだは , おまじな ください いの部分はそのまま使い , そうてないとこ ろだけを自分てプログラムしていきましょ う。さてここて , 重要 プログラミング言語は電卓と違い , い ろいろとめんどうな手続きが必要てあ る ということがわかったと思います。 コンパイルなどを行って作成されたファ イルを実行するときは , ファイル名を打ち 込みます。この場合 , Fig. 3 変数宣言と値の代入 int y; int x; A > listl とします。 数を使う Fig. 2 のプログラムは , 5 と 3 の和を求める プログラムてした。しかし明日になれば 10 と 35 の和を求めたくなるかもしれません。 また , このような単純な計算ならまだしも , 複雑な計算になると途中の計算結果を覚え るなどのために変数を使わないといけませ ん。 数学が嫌いな人は , 中学や高校て、の方程 式などを思い出してイヤな感じかもしれま せんが , その必要はありません。とりあえ ず , 重要 変数は数値などを覚えるための魔法の 箱てある と思ってください さて , 数値を記憶する魔法の箱を使うた 3 である する箱 ( 変数 ) は整数を格納 明解 ANSI C 言語入門講座 111

4. 月刊 C MAGAZINE 1991年4月号

List 10 て、は明らかてあるが , List 8 , List 9 においても文字列定数の値 ( 各文字と最後 の ' \ 0 ' ) が関数 fo 。の実行時に毎回配列 b に対 してコヒ。ーされるのて、ある。このことは実 行効率の低下が起きるかもしれないという ことを意味している。もし auto< ある必要 がなければ , 初期値を伴う文字配列は static にしておくほうが実行速度的には有利てあ ると思われる。 ー数と文ー ーれた配ー List 1 ~ 3 の場合 , puts に渡されたポイン タのポイント先は ( 物理的に変更可能かどう かは別として ) 変更してはならない。一方 , List 5 ~ 8 の場合には , 文字列の長さを延長 しないかぎり , ポインタのポイント先を変 更することは合法的な操作て、ある。一方は 定数をポイントしているのに , 他方は変数 をポイントしているからて、ある。しかしソ ースプログラムの表面的な記述上て、は両者 の差が判然としない。これが第 3 のワナてあ る。なお , List 5 ~ 8 の場合も , 文字列の長 さを延長することが許されないのは , 配列 変数 b のサイズが初期化に使われた文字列定 数の長さにちょうどびったりになるように 確保されているからてある。つまり拡張し た文字列を格納する余地がないのだ。 まちかった文字列の値設定の例 List 11 に文字列定数による変数の値設定 の典型的なプログラムエラーの例を三つあ げておこう。 f001 , f002 はコンノヾイラが工 ラーを発する。しかし , なぜこれがエラー になるのか , ちゃんと理解てきるだろうか ? この中ていちばんこわいのはいうまても なく f003 の場合て、 , これはコンパイラ時に はエラーが発生しない。ただし「値を与えら れていない変数邸 b 〃が使われている」という 警告を発するコンパイラは存在するのだが , List 1 : #include 2 : # i nc 1 ude 3 : 5 : * f001 はコンパイルエラーになる 6 : 7 : VO i d 8 : f001 (void) 14 : } 鷽 * f002 はコンパイルエラーになる 19 : VOid ' 20 : f002 ()o id) 22 : Char 24 : 26 : 28 : } 29 : * f003 はコンパイルエラーにはならない 32 : ー 33 : 34 : VO i d 35 : f003(void) Char 38 : 39 : ・ 40 : く stdio. h> く string. h> b [ 13 ] : Char ” hello, wo ⅵ d ”・ puts(b) : / * 配列には代入できない * / *b = { / * ポインタの場合 , こんな初期化はできない * / 0 puts(b) : strcpy(), "hello, world") : puts(b) : / * コピー先が確保されていない * / List 12 1 : char 2 : *strcat 、 (char *d, const char *s) 4 : Char *d0 5 : 6 : / * ステップ 1 : 文字列 1 の終端を探す * / 7 : while ()d ー 8 : 9 : / * ステップ 2 : 終端の ' \ 0 ' の位置から文字列 2 をコピーする * / / * ステップ 3 : 文字列 1 の先頭へのポインタを返す * / return d0 : 106 C MAGAZINE 1991 4

5. 月刊 C MAGAZINE 1991年4月号

tlsubwin. C List 3 MS-C MS ー C てコンパイルする場合には , 従来と 同様にコンパイルスイッチを設定するとと もに , MS ー C コンパイラのディレクトリ (MSC) 下の INCLUDE ディレクトリの中に , config. h として以下のファイル <MS-C 用 config. h > を入れておく必要がある。 CL /AL /Od /W2 /Zi /J /c 関数 . c ( ラージメモリモード /CodeView を使 用 / 警告レベルは 2/char を unsigned char にする / リンクは行わずコンパイ ルのみ行う ) く MS-C 用 config. h> #define MSC #ifndef MSDOS #define MSDOS 3 : 4 : # i nc 1 ude "config. h" 5 : 6 : #define EXTERN extern 7 : 8 : 9 : #include く coniO. h> 10 : #include "pldwn. h" 11 : #include ”ⅵ ndow. ド 13 : # ifdef PROTOTYPE 14 : #include "cboxprot. h ” 15 : #endif 17 : / * ウインドウ内の特定の属性の追加 19 : tIsubwin(MWINDOW *pw, 20 : unsigned xl, unsigned yl, 22 : unsigned x2, uns igned Y2) 23 : 24 : { 25 : unsigned ylen; 26 : unsigned xlen; 27 : unsigned ystart; 28 : unsigned xstart; 29 : 30 : ー yl + 1 : ylen : x2 ー xl + 1 : Xlen 32 : ystart = yl 33 : xstart = XI subwin(pw, ylen, xlen,ystart, xstart) : 34 : return( の : 35 : 36 : } Copyright 1990 E. TOY0kuni Number T し * / CM910402 #endif #ifndef PROTOTYPE #define PROTOTYPE #endif tlwfresh. c List 4 Copyright 1990 E. TOY0kuni Mod i f i ed 91.01. 18 4 : 5 : # i nc 1 ud e ” config. h ” 6 : 7 : #define EXTERN extern 8 : 9 : 10 : #include く coniO. h> 11 : #include ” pldwn. h ” 12 : #include ” window. h ” 14 : #ifdef PROTOTYPE 15 : # i nc I ud e "cboxprot. h" 16 : #end i f / * ウインドウ内の特定の属性の追加 20 : tIwfresh(MWINDOW *pw, char *title) 22 : { 23 : unsigned xl : 24 : unsigned yl; 25 : uns igned char attr; 26 : ー pw->xl = pw->yl 28 : attr = pw->kattrib ・ wrefresh (pw) : 29 : 30 : printv(title,attr,xl + 2,Y1, の : return ( 0 ) : 32 : } Number T し CM910403 参考文献 WiIIiam James Hunt *The C TooIbox" Addison-Wesley, 1989 [ 追記 ] 前回 ( ' 90 年 3 月号 ) の Tu 市 0 C への移 植記事において , 定数 REVERSE, B 凵 NK のニ重定義問題を # ifdef で処理 しましたが , 実際には筆者の定義した 値と conio. h で定義している値とが必ず しも一致しなかったので , 今回から p 旧 wn. h で定義している REVERSE と BLINK は REVERSEE と BLINKK に改め ることにしました。前回のプログラム についても , 同様に訂正してください。 98 C MAGAZINE 1991 4

6. 月刊 C MAGAZINE 1991年4月号

ルのみのオプション ( / c , -c など ) が指定さ 的に行う。「テンプレート」は「スマート」に とつの . EXE ファイルを作るのて、あれば , れている。また , コンパイル時にエラーが SETUP 時に -c オプションを外しておけばい 構文自動生成を組み合せたものて、ある。 発生すれば工ラーリストのウインドウが開 いが , 複数のモジュールをリンクしなけれ インデント処理の一例として , スマート き , 任意のエラーを選んて、そこに移動て、き インデントの自動化を見てみよう。スマー ばならない場面はいくらて、もある。一般的 トインデントには二つのパターンが用意さ にはこのようなときは , コマンドラインか れている。まず , 第レヾターンを選択する 最後に . EXE .COM ) ファイルの作成とな ら MAKE を使う。 Brief を使用している場合 る。いかなるときもひとつのソースからひ は , 直接 Brief から MAKE を起動すればよ 旧マクロ構文の例 ( BLOCK ー S 印 FT. M ) List printf(.. exit(). ) ; puts(... ) ; こ自動的に処理してくれ というノヾターン ( る。また , 第 2 パターンを選択した場合は , (macro block-shift slide_in slide out) (extern (int direction) (get-parm 0 direction) (save_position) ()f (block-mark) ダイアログボックスを通じて (switch direction 1 (slide-in) 2 (slide-out) (raise_anchor) カーソル位置を保存 プロックがマークできたか 右シフト 左シフト printf(.. exit(). ) ; puts( … ) ; となる。ただし , 第 2 パターンを使いたい場 合は SETUP コマンド終了後に AUTOEX EC. BAT を書き直す必要がある。私見をい わせてもらえば , どちらかというと第 2 パタ ーンのほうをデフォルトにしてくれたほう がよかったのて、はないかとも思うのだが 構文自動生成の雰囲気は FEP の変換に近 い。 w CSPACEJ て、 , while ( ) を生成する。これがおもに制御構文 ( if や for など ) について用意されている。 次に OBJ ファイルの作成。「拡張子ごとに コンパイラを指定て、きる」と説明したが , これは十が押されたときにセット アップ時に設定したコマンドを実行するの て、ある。したがって , やろうと思えばまっ たく関係ないコマンドを起動したり , 別の ェデイタを起動したりすることも可能て、あ る ( もっともそんなことはほとんど意味がな SETUP 時のデフォルトの処理はコンパイ マークを消す カーソル位置を元に戻す (restore_position) (macro block mark ; まず { を探す . ! は論理否定 paren) (extern ()f ( ! (search-back " \ \ { " ) ) (message " { が見つかりません " ) : マークできず (return 0 ) カーソルは { にいる ; マークは次の行から ; { の位置へ : } が有れば : 上の行までがプロック : マーク O K message " } が見つかりません " ) raise—anchor) return の O O 0 れー Q. ー : 相手の } へ進む : e 1 se 132 C MAGAZINE 1991 4

7. 月刊 C MAGAZINE 1991年4月号

す。 GNU bison Ver. 1.11 や GCC Ver. 込み関数」として実装されていて , 引数を評 アウトしてようすを見ることがかなり有効 な手段だと思われます。十中八九工ラーに 1.39 など ( 注 6 ) をコンパイルしてみましたが , 価してそのサイズ分スタックを補正し , ア どれも動きませんて、した。 XC 対応の alloca ( ) なるか , 未定義シンポルて、リンカがエラー ラインメントを行ってその領域をポインタ として返すようなコードを生成します ( 注 4 ) 。 になるはずて、 , 対処はそれから考えたほう を使用して builtin alloca( ) を使用しなかっ た場合て、も , GCC て、はこれらは正しく動き 話がそれましたが , XC のライプラリにはこ が見通しがつけやすいて、しよう。関数の前 から機能が推測て、きるものや , 実際に同じ ますからどうも責任はコンパイラのほうに の関数は存在しませんのて、 , 自作するか 動作をする関数がある場合があるため , そ ありそうて、す。 malloc ( ) に置き換えて最後に free ( ) してやる とくに GCC のコンパイルて、は , 以前説明 れらの情報を駆使 ( ! ! ) して移植を進めていく ことになります。 ことになります。「習うより慣れろ」だと思 した三項演算子の理不尽なエラーのほかに もうーっ注意しなければならないのは , この関数はスタックに領域を確保すること いますのて、 , 今回は実際に動くソースも全 ポインタが指し示す構造体のビットフィー ルドへのアクセス命令にアセンプラが通さ 部あるのて、すから一度コンパイルしてみる になるため , 実行ファイルのスタックサイ ないコードを出力する , 、、 \ 〃て、継続するマ ズに注意してください。 XC て、はスタックサ のがいいと思います。 クロ展開がソースにあると , 工ラーメッセ イズは 64K バイトが標準て、す。 GCC や G 十十 X Ver. 2 での移植の ージの行番号がずれてしまうなどのバグを のように一度に数十 K バイトも確保するよう 可 ~ 性 とくにこの行番号のズレは なアプリケーションて、は容易にスタックを 発見しました。 今向の記事のために , 手元にあるいくつ かなりひどい目にあうのて、注意が必要て、す。 オーバーフローしますのて、十分な注意が必 List 3 を見てください。実際にエラーがある かの GNU ソースを XCVer. 2 て、コンパイル 要て、す ( 注 5 ) 。 行は 15 行目て、すが , コンパイラは 9 行目がお して , その動作試験を行ったのて、すが , 無 このほかにもヘッダが見つからないなど かしいといっています。この場合はコンパ のプリプロセッサ関係のエラーがて、ること 惨な結果に終わりました。 cperf を付録ディ がありますが , まずそのヘッダをコメント スク収録に選んだのは注 3 にあるとおりて、 イラが変なのはすぐわかりますが , この工 ラーの行がたまたまちゃんとしたステート メントの上にあったらひどい混乱を招きま す。これて、 3 時間ほど悩みました。 工ラー行がマクロ呼び出しの上にたまた ま一致していたのて、 , まったく無実のマク ロ定義があるヘッダを呆然と眺めていた とになります。 どうも納得しかねるのは , この行ズレバ グは実際に使用したことがあれば気づくは ずだという点て、す。発売を急ぐことより十 分なテストをしてから発売すべきて、はなか ったか ? とも思えるのて、すが。それから , ANSI て、規定された STDC を定義する のは現状て、はやめたほうがいいのて、は ? と 田います。このマクロはすて、にいくっかの ソースて、テストされていますが , XC Ver. 注 6 XCVer. 1 ては実行ファイルを生成する ことすらてきなかったのて改良はされてい ます。 List マクロの継続があるとエラー行番号がずれてしまう。 2:#define TEST_MAC(P) 4 : char *__p do { 5 : f000 (--p) : 6 : 7 : 9 : 10:extern char buf[] : 12 : fo 。 ( ) 13 : { TEST_MAC (buf) ; 16 : } X68k XC Compi ler v2. 00 Copyright 1987 , 88 , 89 , 90 SHARP/Hudson bug. c 9 : Error 4:undefined identifier in function name : k . 10 :Warning bug. c 15:function return value mismatch. ↑ 行番号がソースからズレている Conference Room 141

8. 月刊 C MAGAZINE 1991年4月号

80186 / 80286 用アセンプラテキスト 能な問題だと思われます。 トランスレータとして考えた場合 また , には C 十十そのものにこだわる必要はないと 田います。どんなに拡張された C 十十て、も , また , PASCAL → C, BASIC → C などのトラ ンスレータを組み合せることも可能て、しよ う。要はパーサに入力されるテキストが , 正統な C の文法に適合していればよいわけて、 すから・・ 識別子での日本語使用 識別子として日本語 ( シフト JIS 漢字コー ド ) を使用て、きるように拡張することは , コ ンパイラを作成するうえて、はほとんど問題 ありません。 ANSI のキャラクタコード規約 からは外れてしまうことになりますが , 文 字列リテラル中において日本語を認識しな ければならない以上 , 同程度の違反て、ある といえます。 ただし , 問題となるのは日本語の識別子 を埋め込まれたオプジェクトをリンカやデ バッガが処理することがて、きるかどうかと いう点て、す。 LINK や PLINK, SYMDEB や CODEVIEW などは , 予測て、きない結果を引 き起こす可能性があります。 もちろん , 専用のリンカ , デバッガなど を作成することによって対応するという手 もありますが , そこまて、するとほかの環境 (MS-DOS 以外の OS や工クステンダなど ) へ の移植性が著しく損なわれることになって しまうて、しよう。 妥協案として「コンバイラ内部では日本語 として識別・処理するが , オプジェクトを 生成する段階ではアスキーコードセットに 適合するように変換する」といったことも考 えられます。これは , その昔 , 日本語対応 のコンパイラがない時代に , フィルターを 使用して文字列中の日本語を文字工スケー プに置き換えていたのと同じような形ての 処理が可能て、しよう。ただし , この場合 , ったほうが処理スピードの点などて、有利に なります。もちろん , トランスレータをコ シンポリックデバッグを行うことはほとん なりますが , RAM ディスクを使用したり EMS ンパイラ本体に埋め込む , または , C 十十の ど不可能となってしまいます。 を採用することなどによりある程度解消可 制御構造を直接解析するといった手法を取 プロジェクト PragmaC 63 List 80186 / 80286 用サンプル Memory mode I : Processor: Optimization: : Pack data: Stack check ing ・ : Defau lt char: String segment: Const segment: し ine numbers: Code=small Data=near Segment=d 80186 / 80286 disabled word 0ff uns i gned data data 0ff 0 . 186 extrn dummy:near CONST, _DATA, _BSS group TEXT group 'CODE' segment byte public assume cs :CGROUP, ds:DGROUP endS ・ CONST ・ segment word public assume cs:CGROUP, ds:DGROUP endS 'DATA ' segment word public assume cs :CGROUP, ds:DGROUP endS DGROUP CGROUP TEXT _TEXT CONST CONST _DATA DATÅ : 001eh , 0 圓 0h : 0000h : 0 圓 0h ・ BSS ・ segment word publ ic assume cs :CGROUP, ds:DGROUP endS 'CODE' segment byte public assume cs:CGROUP, ds:DGROUP pub lic proc enter push push call mov add mov mov mov leave ret end endS end -sample near 十》 4 し・ 0 O ・ 0 0 0 0 00 0 0 一一 0 0 0 0 、 1 14 1 よ、 1 0 0 + 4 , 0 word ptr -b@l [bp] word ptr -a@l [bp] near ptr _dummy word ptr t0@2Cbp], ax sp, 十 4 ax, word ptr t0@2Cbp] word ptr -c@2[bp], ax ax, word ptr c@2[bP]

9. 月刊 C MAGAZINE 1991年4月号

どちらにしろコンパイラ本体には大きな 問題てはありませんのて、 , 以下のようなス イッチを用意しておくことて、対応てきるて、 デフォルト日本語の使用を許可しない -Jk( 仮 ) 日本語を受け付けそのまま出力 する -Ja ( 仮 ) 日本語を受け付け変換して出力 する 読者へのメモランタム 横浜市の山村さん。 longlong 型 ( 64 ビット 整数 ) があると確かに便利て、す。とくに実務 ( ビジネス ) アプリケーションを作成する場 合には double より有益なケースが多いよう て、す。 80386 用て、あれば実現てきるかもしれ ません。 大阪市の歌津さん。 C86PLUS 用て、よけれ ば 88VA 用のランタイムサポート , ライプラ リ ( グラフィック , スプライト , サウンド , PCM そのほか ) があります。ご希望ならソー スを差し上げますのて、編集部まてご連絡く ださい とにかくメモリ不足に悩んて、いるという 方が多いようて、す。機会があればデジタル リサーチの DR ー DOS5.0 , 同 FIexOS286 を見 てみるとよいて、しよう。工クステンダを使 うより楽て、す。 モトローラ 640X0 をサポートせよという意 見がいくつか見られます ( さすがに RISC をサ ポートしろという意見は見あたりません ) 。 アンケートから はてな最適化はやらなくてよい 0PragmaC には , 安全て、確かなコードを出力してほし い。また , これからのことを考えて , 32 ビ 64 C MAGAZINE 1991 4 パイラと同じようになってほしくはない コンパイラを作るのだから , そこらのコン い伝統を守ることはない。せつかく新しい ットに対応していくべきだ。 16 ビットの古 C 文法を改善するぐらいのことはしてほし い。それから MS-C を気にしすぎているよう だが , 気にしなくてよい。 PragmaC が MS -C を変えるぐらいになればよい 千葉県吉田要 オリジナルという以上 , SmaI ℃の拡張程 度や貴誌の C マイナー程度て、は問題がある。 したがって , 市販言語と競り合うというこ とになると , 全メモリモデルのサポートが 大衆的条件といえる。 CPU のサポートはモ デルチェンジというわけにもいかないのて、 それほど考える必要はないと思う。浮動小 数点演算も同様て、ある。仕様 , ライプラリ は ANSI C は当然として , ほかとの差別化と して , module 化のサポートなどがあるとう れしい ( もっとも , そのぶん仕様は複雑にな るが ) 。そのほかとしては , debugger,profiler, インタブリタがあるとよい。さらにフロッ ビーて、使えればなおよいが , Turbo C 十 CodeView という感じになってしまいそう だ。また Cmagazine の性質上ソースを公開 する手もある。 今回はコンパイラの仕様ということて、す が , 統合された開発環境として何を作成す るのか ? ( デバッガ , 工デイタ , リンカなど ) についてもアンケートしてみてはいかがて、 しようか ? 神奈川県藤川礎久 すべきだ。 神奈川県坂野晃弘 PC98 がホストて、もよいから , 68000 , V60,TRON などほかの CPU への対応を検討 してほしい。 CPU アーキテクチャに依存す る部分と依存しない部分を分けてコーディ ングされたコードジェネレータ , オプティ マイザにしてくれれば , 第三者が対応て、き る。 86 系だけて、はメリットがない ( 苦労して 作るより買ったほうがよい ) 。 東京都塚元卓 現在 , システム開発においていちばん気 になるのがメモリの制約 ( 640K バイト ) て、 す。そこて、ェクステンダの機能はコンパイ ラの仕様に盛り込んて、ほしい ( リンカも独自 になってしまうのかなあ ! ) 。 ライプラリは ANSI,UNIX のみサポート し , それ以外は PM みたいにマネージャとし て OS ( デバイスドライバ ) レベルて、サポート やたらに型を追加するのはよくないと田 じ、 いますが「制御が戻らない関数型 (exit( ),lon gjmp() など ) 」 , 「書き込み。 nly 型」があると おもしろいと思います。 ” stdarg. h"va arg( ) 中て、 sizeof を使用す る場合に ( ポインタのインクリメントて、も同 じことて、すが ) char 型て、” sizeof(char) = となる仕様ならば正しくインクリメントす るマクロ設定が必要ぞす ( スタック上て、は char て、も偶数バイトを占めていると思います ) 。 福井県山川隆央 ① Forth のように「関数ごと」に実行テキスト / チェックて、きるようにしたい ②専用工デイタて、 , プログラムのソースを 書いている間も「行ごと」に文法チェック をさせる ③トップダウンて、書けるように専用工ディ タに「アウトラインプロセッサ」の機能を 「積極的」にもたせる京都府佐伯俊 どんな機種 ( つまり FD モデルしかない読者 ) て、も不都合のないようなものにしてほしい 最近はハードディスクが当たり前て、あるが , そのためにもコンパイラ自体はもちろんの こと , ライプラリもて、きるだけ重くならな いようにして , 必要に応じて結合て、きるよ うにしほしいと思います。私は 98 ューザて、 すが , て、きたら汎用 DOS 版 (MS-DOS) にし てほしい。最初からマニアックなコンパイ ラて、はなくてもよいと思います。少しずっ バージョンアップしていけばよいのて、すか 東京都高橋康成

10. 月刊 C MAGAZINE 1991年4月号

コレエス・アイ・ジャ / レ lnformation from C0mpiler Makers Q&A Q LSI C ー 86 で次のような演算を 実行すると , x の値がなぜ 999 でなく 998 になるのでしようか ? LSI C- 80 でも同様な結果になるのですが。 int double a : 対策としては , たとえば整数に 変換する際に四捨 li. 人する方法が 号えられます。これは , 次のよう に整数に変換する直前に 0.5 を足す ことにより実現て、きます。 double a : a 0 .999 ; 1000 ) 十 0 . 5 a X A 0 . 999 : a * 田 00 これは浮動小数点数の内部表 現に起囚する間題て、す。 LSI C- 86 , LSI C ー 80 やそのほか多くのコ ンパイラて、は , 2 進法て、数値を表現 しています。 浮動小数点数て、も同様て、 , たと えば 0.5 という数は 2 進法て、は 0.1 と 表されます。ところが , 0.999 は 10 進法て、は有限桁て、表記て、きますが , 2 進法て、は 0 .111111111011111001110110 110010001011010000111 ・・・ と , 循環小数になってしまいます ( 1 / 3 が 10 進法て、は 0.33333 ・・・ なるのと同じて、す ) 。 浮動小数点数のビット数は有限 なのて、 , このような場合 , ドのほ うの桁は切り捨てられることにな ります。そのため , この数を 1 , 000 倍しても正確な 999 にはならず , 998.99999 ・・・・・という数になってし まいます。 そして , C て、は浮動小数点数を整 数に変換するとき , 切り捨てを行 う約東になっているのて、 , l•. 記の 数は 998 になってしまうのて、す。 152 C MAGAZINE 1991 4 LSI C ー 80 でアセンプラとして PROASM ー収岩崎技研工業と京都 マイクロコンピュータの共同開発 ) を使用したいのですが , どうすれ ばよいのでしようか ? A LSI Cー80 て、 PROASM-II を使 Ⅲする場合は , 次の 2 つの方法があ ります。 Q ・ライプラリを PROASM-IIJIJ りなおす。 ツール ) を PROASM-IIJIJ に作 ・ 1CC80 , libr80( ライプラリ作成 がかかります。 が必要になりますのて、多少時間 Ⅲします。この場合は次の準備 2 PROASM-II のリンカ LNK を使 にコン / ヾ ートしてリンクします。 ファイルを SOF 形式のファイル ルした後 , re12sof て、 REL 形式の ースを PROASM-II て、アセンプ ます。この場合はアセンプラソ 1 LSIC-80 のリンカ knil を使用し に作りなおす。 以 l•. , 2 つの場合のコンパイル方 make を使Ⅲする場合を説明しまし 使用すると簡甲 . にて、きますのて、 , 法を説明します。どちらも make を makedef というファイルは make を起動する際に必要になるファイ ルて、す。 LSIC ー 80 パッケージに入 っています。 て、なく . mac にします。ただし , ア るソースファイルの拡張丘は . asm めに , PROASM-II て、アセンプルす て、 SOF 形式ファイルに変換するた て、アセンプルされたものを re12sof make て、自動的に PROASM-II イスク参照 ) のように変更します。 まず , makedef を List 1 ( 付録デ 1 LSI C ー 80 のリンカを使用する場 とします。 センプラはザイログニーモニック す。 H に配置してリンクするものとしま します。 ROM を 0 番地 RAM を 8000 test. c が C 言語のソースファイルと て、アセンプルするソースファイル , す。 testasm. mac を PROASM- II クの makefile の例を次に示しま ROM 化の場合のコンパイルリン LSI C ー 86 て次のようにコンパ るオプションを指定します。 define PROASM" を挿入す コンパイルのときに、、 # 作成します。 ンパイラドライバ lcc80r. exe を パイルし , PROASM-II 用のコ 1CC80. c を LSI C ー 86 て、再コン 1 LSI C ー 80 パッケージ中の 次の丁・順て、環境を準備します。 2 PROASM-II のリンカを使用する $@ $ # -fa:*c*romlib } knil @$ { $(LFLAGS) test. sof test. hex : testasm. sof #DATA=8000 LFLAGS = ー旧 #CODE=O LSI C 80 LSI C 86 イルします。 lcc -dPROASM ー 0 に c80r. exelcc80. c 2 同様に libr80. c を LSI C ー 86 て、 再コンパイルし , PROASM- Ⅱ用のライプラリ作成ツール libr80r. exe を作成します。 次のようにコンパイルしま す。 lcc -dPROASM ー 0 libr80r. exe libr80 . c 3 PROASM-II 用のライプラリ を作成します。 PROASM-IIJIJ ライプラリ 作成の makefile を List 2 ( 付 録ディスク参照 ) のように作成 します。 LSIC ー 80 パッケージ中 のライプラリ作成の makefile を参考・にして作成してくださ makefile がて、きたら LSI C ー 80 パッケージからライプラリ . asm て、なく . mac にします。 ソースファイルの拡張子は ックて、書いたアセンプラの 別するためにザイログニーモ ンプラのソースファイルと区 ンパイラから出力されるアセ パイルて、きます。この場合コ 以 E の準備がて、きたら , コン リにいれて環境を整えます。 rel をライプラリのディレクト ライプラリ clib. rel や romlib. うに変史します。 List3 ( 付録ディスク参照 ) のよ 4 PROASM-II 用に makedef を して make します。 のソースファイルををコヒ。ー 5