変数 - みる会図書館


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

1. 月刊 C MAGAZINE 1992年4月号

3 変数 、一 SECTION 使い方が 制限される名前 的な制限 ・関数のネーミング法 最後に , 名前のつけ方について考えてみ ます。名前というのは , 具体的には変数名 , 関数名などて、す。 まず , つまらない条件からチェックして おきますと , C 言語の仕様により予約されて いる名前は自由に使うことがて、きません。 これらは用途が決まっているのて、 , プログ ラマが勝手に使うことはて、きません。もち ろん , それを無視するとコンパイルする時 点て、多分工ラーになるのて、 , 予約語は変数 名に使えないということさえ頭に入れてお けば , うつかりしても , たいへんな混乱に 至ることは希だと思います。 また , コンパイラやリンカなどの処理系 の制限によって , 一定の長さ以内にしなけ ればならないこともあります。 長さといっても , 最近の処理系だと , 実 用的に十分な長さの名前を自由につけるこ とがて、きるのて、 , ほとんど気にしなくても まず問題ないて、しよう。 かっての BASIC のように , 先頭の 2 文字し か判別に使われない言語があって , a01 と a 02 が同じ変数とされてしまうのて、難儀した といったような苦労は , すて、に昔話として 語り継がれているにすぎません。昔話をも うひとっしておくと , 昔は , 変数名が短い ほうがメモリやディスクの使用量が少なく て済む , といった苦労もありました。 C 言語は基本的にコンパイラの環境が提供 されているため , 変数名とメモリは直接関 係ないように思えるかもしれませんが , メ モリが 64K バイトもあれば大容量といってい た時代には , 変数が長すぎるとコンパイル 64 C MAGAZINE 1992 4 の途中て、メモリが足りなくなってしまった り , ソースファイルが長くなるためにディ スクの空き容量が不足してコンパイルに失 敗するという , 今て、は想像もて、きない世界 があったのて、す ( 1 ) 。 取り敢えず , もはやコンパイル時にメモ リを気にする時代は終わったと考えておく 話がそれますが , 実行形式のプログラム が消費するメモリ量は , ますます少なくな ることを要求されています。 今後はパソコン上て、マルチタスクの環境 を実現する方向へ世界が向かっているから て、す。個々のプログラムが小さくても , プ ログラムを 10 個同時に走らせようとすると , 10 倍のメモリが必要になるかもしれません。 640K バイトのメモリが必要なソフトを 10 個同時に実行するには , 単純に考えても約 6M バイトのメモリが必要て、す。もちろん , 実際は , あの手この手のメモリ管理を行う ため , 共有て、きるコードを共有したり , メ モリが足りなくなったとき , あまりアクセ スされない領域を一時的にディスクに待避 するなどして , 何とか少ないメモリをやり くりするのて、す。 それぞれのプログラムがメモリの使い方 に無頓着かどうかて、 , 全体の使い勝手に多 かれ少なかれ影響することは間違いないて、 という話は今回は全然関係ないのて、 , 取 り敢えず , 変数名 , 関数名の話に戻ります。 Fig. 2 C 言語の予約語 auto defa ult float 「 egister struct volatile break do fo 「 etu rn switch while case double goto short typedef Char else signed umon まず , 予約語 ( Fig. 2 ) は自由な用途には使 えないということを書きました。これはひ とまず問題ないて、しよう。 次に問題になるのは , 予約語て、はないの だが , 自由に使うのは避けたほうがいい名 前て、す。たとえば , C 言語には標準的な関数 がいくつか決まっています。これらと同じ 名前の変数名を使うことは可能て、す。しか し , それは混乱を生むだけて、何のメリット もありません。とくに , ANSI て、定義されて いる関数の名前は , それ以外の用途に使う ことは避けるべきて、す。 たとえば printf や fopen という変数名を使 ってはいけません。後て、プログラムを読む 人が混乱するかもしれないからて、す。また , 自分て勝手に定義した関数に printf という名 前をつけるのは感心しません。もちろん , それが一般的な printf を模倣するための処理 て、あるなら , 話は別て、すが。 さらに次のアドバイスは必須というほど て、はなく , おすすめ程度のニュアンスて、考 えてほしいのて、すが , 原則としてほかの言 語の予約語は , てきるかぎり使わないほう がよいと思います。とくに , C 言語に非常に 近い言語として , C 十十というものがありま す。 C 十十には , C 言語て、は予約語とされて いないいくっかの語が , 新たな予約語とし 予約された名前 VOid static long exte rn continue て追加されています。とくにこれらの予約 unsigned sizeof i nt enum const

2. 月刊 C MAGAZINE 1992年4月号

List 2 10 : VAR 13 : (.. 56 : 55 : 54 : 52 : 50 : 49 : 48 : 46 : 51 : END ・ Scratch END ・ Variable . N_Value ・ Value Undefined 53 : BEGIN Valid : = TRUE : Non Contradictory Evaluate (Tree) ・ 57 : END ・ ニ FALSE ・ List 3 49 : 45 : 44 : 42 : 40 : 39 : 38 : 36 : 35 : 34 : 33 : 32 : 30 : 29 : 26 : 25 : 24 : 23 : 22 : 20 : 11 : 9 : 8 : 6 : 5 : 4 : Reduce 関数 式を還元 ( 単純化 ) する 7 : FUNCTION Reduce ( p: Subs_Var: Pointer Pointer) : Pointer 14 : FUNCTION Reduce_Not : Pointer ・ 15 : FUNCTION Reduce_And: Pointer ・ 16 : FUNCTION Reduce_0r : Pointer ・ 17 : FUNCTION Reduce_Impl : Pointer ・ Left, Right, q: Pointer ・ 0perand : I F P ニ Subs—Var THEN Reduce ELSE Reduce CASE N_Type OF WITH DO ELSE = NIL Reduce IP P = NIL THEN 21 : BEGIN 19 : 以上が別途作ってある ... } 18 : FUNCTION Reduce_Equiv: Pointer Truth Value: IF N Truth_Value THEN ニ F_Node ・ = T Node = F Node Reduce ELSE Reduce ・ニ T_Node IF 戓 . N_Value = Value TRUE THEN ELSE Reduce ・ opera tor : BEG I N Left CAS E N_0perator OF Op—Not 0 p—And 0p-0r = Reduce (N_Left_Link, Subs-Var) Right ド Reduce (N—Right-Link, Subs—Var) ・ Reduce ・ = Reduce_0r Reduce ・ : Reduce_And Reduce ・ = Reduce_Not Reduce は , このアルゴリズムの中核部て、 す。パラメータは , 還元 ( 単純化 ) すべき式 て、あり , その式に対応するツリーを指すポ インタと , 値を真理値て、置き換えた変数を 表すノードて、表されます。 この関数は , パラメータとして渡された コンパイラに関する参考書ならどれにても 技法を使っています ( アルゴリズムの詳細は このプログラムは , 変換のための標準的な を > , 等価を = て書き表すことを求めます。 ラムは not を一 , 合接を . , 離接を第含意 使える文字に制限があるため , このプログ 換し , そのツリーを評価手続きに渡します。 書かれた式を受け付け , それをツリーに変 きますから , プログラムは通常の直線的に もちろん人間は , ツリーてはなく式を書 関数を List 5 に示します。 用されます。例として , 条件式を処理する 部的関数によって , Quine の単純化定理が適 そしてサブツリーに対して作用する 5 個の内 ツリーがまず再帰コールによって還元され , ノードは一つの演算子て、す。左右のサプ れば , 結果はそのノードて、す。 関数の結果はその真理値て、す。そうて、なけ 変数が真理値に置き換えられた変数ならば , ノードは一つのオペランド ( 変数 ) て、す。 返されます。 し , 関数の値として T node または F node が ノードは一つの真理値て、す。還元が終了 す。 List 3 の PascaI の CASE 文の説明をしま 各ノードをそのタイプに従って処理します。 らスタートして , ツリーを下へ降りていき , ぞれ真と偽を表現します。関数はルートか れる Truth value 型の 2 つのノードて、 , それ T node と F node は , 初期化のときに作ら します。 ポインタはつねに曖昧さなく , 変数を同定 って変数を表現しますから , ノードを指す の式中の変数に結びついている / ードを使 リー ( 式 ) を返します。評価の全段階て、 , 元 変数がその中にもはや存在しないようなツ 真理関数論理のためのスクラッチバッド 27

3. 月刊 C MAGAZINE 1992年4月号

メンバ関数ファイルは , クラスが持つメ ンバ関数群を定義するものて、 , ファイルの 先頭て必ずそのクラスが定義されているフ ァイルをインクルードしています。実際に は , 各クラスの定義部分て、 , プロトタイプ 宣言されているメンバ関数群の実体を持っ ています。 このファイルの実体は C 十十ソースプログ ラムて、す。ソースをコンパイルしたものが オプジェクトプログラムファイルとなります。 これら三つのファイルはすべてクラス名 をファイル名としており , 拡張子によって 区別されます。このように , NIHCL クラス ライプラリのファイルは , 1 クラスについ て , クラス定義 , メンバ関数定義 , オプジ ェクトプログラムの三つのファイルから構 成されています。これは NIHCL だけて、な ほかの多くのクラスライプラリて、もユ ーザへの提供形態はこうした 3 本立てのファ イル構造をとっています。 こうしたファイルの構造は , 前述 実は , したライプラリの再利用と重ねてみた場合 , 非常によく考えられたメカニズムを持って います。閉じた再利用と開いた再利用のど ちらの場合て、も , クラスの定義がユーザプ ログラムから認識可能て、なければなりませ ん。したがって , クラス定義ファイルをイ ンクルードします。その中て、プロトタイプ 宣言されている関数の実体はオプジェクト プログラムファイルにあります。よって , オプジェクトファイルをリンクすることに よって , 完全なクラスの再利用が行えると いうことになります。ところが , このよう なクラスライプラリに新たなクラスを派生 させて , 開いた再利用としてライプラリを 利用する場合 , クラス定義ファイルをイン クルードしてオプジェクトプログラムファ イルをリンクする機構て、は不都合が生じて しまいます。 クラスを用いて , 開いた再利用を行うに はふたっ方法があります。まず , 既存のク ラスに新たなクラスを派生させ , クラス階 層を作る方法て、す。これをオプジェクト指 向の世界て、は , サプクラッシングといいま すが , C 十十のサプクラッシングは , Smal 108 C MAGAZINE 1 2 4 Fig. 1 N 旧 CL クラスライプラリのクラス階層 ( 一部 ) N 旧 CL Object B itset Class Collection ltalk ー 80 とは異なり若干複雑て、す。 こて、 , クラス階層について再度考えて みましよう。クラスは , 変数とその変数に 対する操作関数を持ったものて、すから , 派 生クラスによって既存クラスに定義されて いる変数と関数の再利用 , 既存クラスへの 変数と関数の追加 , そして関数の再定義 ( こ れをオーバライドと呼びます ) を行えます。 この派生機能のうち , とくに変数の再利用 を中心にした機能を開いた再利用と呼ぶわ けて、す。 ところが , SmaIItaIk-80 と違って C 十十は クラスのメンノヾごとに ,public や purivate な どの属性を持っことがて、きます。そして , 派生の仕方と変数の属性の組み合わせによ って , 新たなクラスを持っ変数の属性が決 定します。派生クラスを作るためには , 大 きく 2 種類の派生方法があります。その違い は , 基本クラスを private にするか public に するかの違いて、す。 基本クラスを private にする場合 , 定義方 法は , Fig. 2 (a) のようになります。 この場合 , キーワード pr ⅳ ate を省略する ことがて、きます。つまり , 省略した場合 , この派生方法になるわけて、す。このとき , 基本クラスの全メンノヾは派生クラスの priva Arraychar ArrayOb Bag SeqCltn Heap LinkedList OrderdCltn S 0 rted Cltn KeySortCItn Stack Set Dictionary ldenDict ldentSet

4. 月刊 C MAGAZINE 1992年4月号

ログラミング 年月日を入力すると曜日を出力する (dayweek. c) List TabIe 1 if のカッコの中に入る条件式 条件式 意味 b 1 : / * dayweek. c * / 2 : #include く stdiO. h> 3 : int main() int year, month, day, dayofweek; 5 : printf(" 年 ( 西暦 ) ? ” ) ; scanf("Xd ” , &year) : printf( ”月 ? ” ) : 9 : scanf( ” Xd ” , &month) ; 10 : printf( ”日 ? ” ) ; 11 : scanf("Xd", &day) ; 12 : if (month く 3 ) { 13 : 14 : year— 15 : month + = 12 ; 16 : (year 十 year / 4 ー year / 17 : dayofweek 100 + year / 400 + ( 13 * month + 8 ) / 5 + day) % 7 ; if (dayofweek = 19 : printf( ”日曜日 *n"); 20 : else if (dayofweek 21 : printf( ”月曜日 \ n ” ) ; 22 : else if (dayofweek 23 : printf( ”火曜日 *n") ; 24 : else if (dayofweek ー 25 : printf( ”水曜日 *n") ; 26 : else if (dayofweek printf( ”木曜日 *n ” ); 28 : else if (dayofweek 29 : printf( ”金曜日 *n"); 30 : else if (dayofweek printf(" 土曜日” ); 32 : 33 : return 0 : 34 : } 【注意】 List 5 の注意をこ覧ください ・・注釈 ・・・入出力の準備 ・・・以下がプログラムの主要部分 ・・・ int 型の変数 year, month, day, dayofwee k を用意 ・・「年 ( 西暦 ) ? 」と出力 ・・・ yea 「の値をキーポードから入力 ・・・以下同様 a は b に等しい a は b に等しくない a は b より小さい a く b a は b より大きい a > b a は b 以下である a く = b a は b 以上である a > = b TabIe 2 変数の値を増減する命令 意味 変数 x の値を 1 増やす x 十十 : 変数 x の値を 1 減らす 変数 x の値を a 増やす X 十 = 変数 x の値を a 減らす を増やしたり減らしたりする命令 year— month 十 = 12 ; が使ってあります。 変数の値を増減する命令には , TabIe 2 の ようなものがあります。 x 十十 ; を と書いてもかまいません。また と書いても同じ意味になりますにの最後の 書き方がほかの言語ては一般的て、す ) 。 このプログラムて使った曜日の計算式は 「ツェラーの公式」と呼ばれるものの一種て す。この公式を理解する必要はありません。 長い数式はこのように 2 行以上に分けて書く ことがてきます。 ご質問やご要望は 〒 108 東京都港区高輪 2 ー 19 ー 13 NS 高輪ビル ソフトバンク ( 株 ) C マガジン編集部 「ステップ C 」係 まてご遠慮なくお寄せください ・・もし month が 3 より小さいなら ・・・ yea 「を 1 だけ減らし , ・・・ month を 12 だけ増やす ( つまり 1 , 2 月は前年の 13 , 14 月とする ) ・曜日の計算式 ・・もし dayofweek が 0 なら ・「日曜日」と出力 ・・そうでなく , もし dayofweek が 1 なら ・「月曜日」と出力 ・・・以下同様 ・・正常に終了したという合図 Fig. 5 if 文の使用例 5 1 っ 4 令令 (b) if (x く 5 ) Fig. 6 else と組み合わせた例 令令 令令 命命命命 実践 C プログラミング入門 105

5. 月刊 C MAGAZINE 1992年4月号

ぶことになります。デフォルトの 状態ては , 各言語の名前付け規約 の条件は , Table 3 のようになりま す。ただし , コンパイルオプショ ンなどにより , 条件が変化する場 合があるのて注意が必要てす (Tab le 4 ) 。 言語によってシンポルとして使 用て、きる文字に制限があります。 また , 大文字あるいは小文字をシ ンポルとして使用したい場合があ ります。このようなときには , AL IAS を使って任意のシンポルを生 成させることがて、きます。 呼び出し規約 呼び出し規約とは , 関数やプロ シージャを実際に呼び出すときの マシン語レベルての手順てす。 の手順が , 呼び出す側と呼び出さ れる側とて一致していないと重大 な障害となります。呼び出し規約 ては , パラメータを受け渡す方法 , パラメータを渡す順序 , スタック の調整方法が規定されています。 マイクロソフトの言語製品ての呼 び出し規約は Fig. 1 に示すとおり てす。 引数の受け渡し規約 一般にパラメータの受け渡し方 う。 ているかを解析するとよいて、しょ れた側がどのようにデータを返し を受け取っているか , また , 呼ば 呼び出した側がどのようにデータ 成するアセンプラコードを読んて , て戻したい人は , コンパイラの生 いろいろなデータを関数値とし えます。 e を使って値を得たほうが簡単に行 以外のデータは Call by Referenc は簡単に行えます ( TabIe 6 ) 。それ 4 バイト以下の整数値を返す場合 関数の戻り値 5 のようになっています。 各言語て、の受け渡し規約は Table 正しくパラメータが渡されません。 る側とて、同じ方法を用いないと , きます。呼び出す側と呼び出され れた側て、内容を変更することがて 渡す方法て , 変数てある場合呼ば ference はパラメータのアドレスを てす。これに対して , CallbyRe alue はパラメータの値を渡す方法 ばれる方法があります 0CaIIbyV れる方法と Call by Reference と呼 法としては , CallbyValue と呼ば lnformation from Compiler Makers Fig. 1 マイクロソフト言語製品での呼び出し規約 く C の呼び出し規約 > バラメータはスタックを介して渡されます。引数は右から左の順でスタ ックに積まれます。スタックの調整は呼び出し側で行います。 <BASlC/FORTRAN/PascaI の呼び出し規約 > バラメータはスタックを介して渡されます。引数は左から右の順でスタ ックに積まれます。スタックの調整は呼び出される側で行います。 ※これ以外に , C で fastc 訓を使用したときのレジスタを介してノヾラメータ を受け渡す規約があります。しかし , この規約は C でのみ使える規約でミ ックスドランゲージでは使えません。 TabIe 5 引数の受け渡し規約 引数の受け渡し方法 BASIC Pascal FORTRAN CaII by VaIue Call by Reference CaII by Reference Call by VaIue ※ C 訓 by Reference による引数受け渡しでは , アドレス ( ポインタ ) を渡すために nea 「 ポインタか fa 「ポインタかの注意も必要です TabIe 6 関数の戻り値が格納されるレジスタ ( 4 バイト以下の整数値 ) 言語 C 注 ) BAS ℃ FORTRAN パイト数 TabIe 3 言語 BAS ℃ FO RTRAN TabIe 4 言語 BAS ℃ FORTRAN 名前付け規約 ( テフォルト ) 、ンハルの文字 条 件 31 文字までシンボルの先頭にアンダースコア ( ) をつける 40 文字まで大文字に変換する 31 文字まで大文字に変換する オプションによる名前付け規約の条件変化 データ型 Char int, short near * long far * INTEGER ( % ) LONG(&) オプション 条件 2 4 上記以外のテータ lNTEGER*2 lNTEGER*4 -pascal* たは fo 市 an を使用すべて大文字に変換 , ジスタ AL DX 高位の部分 AX 低位の部分 DX セグメント部分 AX オフセット部分 AX 低位の部分 DX 高位の部分 猷データへのオフセット値 AX 低位の部分 DX 高位の部分 AX CDECL を使用 C 属性を使用 先頭にアンダースコアはつけない すべて小文字に変換 先頭にアンダースコアをつける ピリオド (. ) をアンダースコアに変換 すべて小文字に変換 先頭にアンダースコアをつける 注 ) ・ float または doub 厄を返す場合には , その値をグローバル変数 fac にコ ピーし , fac のアドレスをポインタ値として返します。 ・ long doub 厄を返す場合には , 値をコプロセッサ命令を使いコプロセッサ スタックのトップに置きます。 ・構造体を返す場合には , グローバル変数に構造体をコピーしてそのアド レスをポインタ値として返します。 lnformation from Compiler Makers 157

6. 月刊 C MAGAZINE 1992年4月号

2.0 との比較も行っていますが , -02 による 最適化を行っても , BC 十十 3.0 のコンパイル 内 のほうが高速て、あるという結果が出てしま ー 0 -Ob -Oe -Og -Oi ー -Om -Op -Ot -Ov -k- ー Z の指定と同じ もっともスピードが速くなる ー 0 -Ob -Oe -Os -k- - Z の指定と同じ もっともサイズが小さくなる ジャンプのオプティマイズ プロテクトモード ポインタの工イリアスがないことを仮定 必要のない変数への代入を削除 BC 十十 2.0 て、は , bc. exe と bcx. exe のふた プロックスコープ内の共通式をくくり出す オプティマイズを一切しない つの環境版コンパイラがありました obc. ex 大局的なレジスタ割り当てと , 変数のライフタイム解析 関数内の共通式をくくり出す e が , VROOMM によるメモリ管理を行う従 memcpy, strlen などをインライン展開する ループを「 ep / stow などへ置き換える 来どおりの環境版コンパイラ。 bcx. exe は , 式をループの外へ追い出す 定数値・変数値の伝範 VCPI により Extended Memory を使用する サイズか小さくなるようなコードを生成 スピードが速くなるようなコードを生成 286 / 386 / 486 て、しか動作しない環境版コンパ ループ変数の置き換えと演算の強さ解析 イラて、した。同様に , bcc. exe と bccx. exe が スピードが速くなるようなコード生成・ MS ー C との互換のため 値のレジスタへの再ロードを抑制する 提供されていました。 fastc 訓呼び出しを有効にする ( 引数のレジスタ渡し ) BC 十十 3.0 て、は , bc. exe と bcc. exe の一系 あることが見て取れます ( この式は , ' 92 年 わけて、す。 統だけが提供されます。名前こそ 2.0 の VR 2 月号の特別レポートて、 , SVR4 / 386 コンパ また , BC 十十 2 . 0 に比べてもコンパイルは OOMM 版と同じて、すが , 内実は Extended イラの最適化を評価するのに使った式と同 高速になっています。 Table 2 て、は , BC 十十 Memory を使用するものて、す。 Extended Me じなのて、 , 興味のある方は比べてみてくだ List 3 のコンバイル結果 ( 2 ) 式のループ外への追い出し , ループのス トリング命令への置き換えなどを List 6 に示 します。 TabIe 1 オプティマイズ関係のオプション スイッチ ー 02 ー 01 ー 0 -Oa -Ob -Oc -Od -Oe -Og -Oi -Om -Op -Os -Ot -Ov -Ox LiSt 1 : / / ー 02 でコンパイル 2 : / / 式の結果を printf で表示して中身の消失を防いだ 3 : void expr2() 4 : 5 : assume cs:_TEXT 6 : @expr2$qv proc 7 : push 8 : bp, s p mov 9 : sub sp, 2 10 : int a = 1 , b = 2 , c = 3 ; mov word ptr CbP-2], 3 13 : a = a 十 b 十 c; / / なんと即値で計算している ! 14 : bx, 1 add bx, 2 add bx, 3 17 : b = a 〉〉 1 : / / ちょっと無駄が残っていますね ax, bx 田 OV ax, 1 ÄOV CX, ax a = b % 10 : 22 : bx, 10 田 OV / / これはいったい・・・ ? cwd 24 : bx / / ax への再ロードはない idiV bx, dx 田 OV printf( ” a=Xd b=Xd c=Xd%n ” , a, b, c) ; word ptr Cbp-2] push 28 : push CX 29 : push dx ax, offset DGROUP:s@ 30 : ÄOV push near ptr —printf 0a11 add sp, 8 sp, bp 重 OV POP ret 38 : @expr2$qv endp コンバイル速度 near さらに驚異的なのは , そのコンパイル速 度て、す。 Table 2 はオプティマイズオプショ ンとコンパイルに要した時間て、す。ここて、 は , DOS のコマンドラインから , bcc. exe を 起動して複数のソースのコンパイルにかか る時間を測定しました。 -02 オプションと , -Od オプションて、のコ ンパイル時間は , それほど変化がありませ ん。それなのに , 出てくるコードは段違い に良質なものてす。 マニュアルの記述によれば , -02 オプショ ンを指定すると 50 % のコンパイル速度ダウ ンということて、したが , bcc. exe て、はそれほ ど差が出ませんて、した。 以上のように , BC 十十 3.0 のオプティマイ ズは , 強力て、あるうえに とっても高速。 TurboCVer. 1.5 の夢よもう一度 , という 33 : 34 : -0 6 行ー 3 3 00 37 ・速報米国版 BorIand C 十十 Ver. 3.0 & Application Frameworks

7. 月刊 C MAGAZINE 1992年4月号

工ル・エス・アイジャパン lnformation from C0mpiler Makers LSI C ー 80 LSI C ー 86 開始時に初期化されます。 扣問 ・・円周率 ・自然対数の底 Q double LSI C -80 で回転 (rotate) 関数 ・ 180 / 円 DEG double はどのように記述するのでしよう calc の使用例を示します 0Fig. 1 double のように式を入力すると , その値 を計算して表示します。 A double 回転関数はいくっか実現方法 double LSI C -86 Ver 3.3 の がありますが , C 言語て記述する方 新しいバグ情報 double 法とアセンプラて記述する方法の double ・ライプラリのバグ サンプルプログラムを付録ディス クに収録しましたのて参考にして 構造体の代入を行うと正しく動 かないことがあります。構造体の ください ( 付録ディスク LISTI , L log (double x) : double 代入ルーチンて一部のレジスタが IST2)0 なお , C 言語て記述する方 log 1 0 (double x) : double 法はほかの処理系への移植性があ 待避されていないためてす。 sqrt(double ) : double りますが , アセンプラて記述する 回避方法としては構造体の代入 fabs(double ) : double ルーチンてレジスタを破壊しない 方法は LSI C ー 80 だけて使える方法 frexp(double x, int * p) : double ようにします。次の手順てライプ ラリを変更します。 ( 1 ) List 3 のソースを MOVSX. p8 ー LSI C -80 の数学関数 6 というファイル名て作成しま LSI C ー 80 Ver 3.1 には数学関 す。 数ライプラリは含まれていません。 ② ソースをコンパイルします。 そこて数学関数の一部をまとめた A > lcc -c MOVSX. P86 ( 3 ) 次のようにライプラリを変更 ものをご紹介します。ソースファ して , 新しいものと入れ換え イルは付録ディスクに収録しまし た omath. c には Table 1 に示した関 数が含まれています。 math. c はラ A>oar Ⅳ doslib MOVSX イプラリ化されていませんが , 実 旧 C -86 の講習会 際にご使用になるときはライプラ お知らせ リ化したほうがよいてしよう。 calc. c はテスト用に作成した簡易 3 月より定期的に LSI C ー 86 の講 電卓プログラムてす。 calc. c をコン 習会を開催する予定てす。場所 , パイルするときには浮動小数点用 日程 , 受講料などは次回のこのコ printf ライプラリ flib. sof をリンク ーナーてお知らせします。お問い してください。 1CC80 てオプション 合わせは下記まてお願いします。 ー lflib て指定します ocalc.com の実 、エル・エスアイジャパン株式 行には CP / M 工ミュレータが必要に 会社 営業企画部越石 なります。 calc は関数計算と四則演 TEL : 03 ー 3404 ー 1341 算 , 代入と変数を使用てきます。 たくさんの方のご参加をお待ち 変数は大文字と小文字を区別しま す。 calc ては次の三つの変数は実行 しております。 160 C MAGAZINE 1 2 4 math. c に含まれている関数 TabIe 1 関数 sin (double x) : cos(double x) : tan (double x) , 機能 正弦関数 余弦関数 正接関数 ー 2 からな / 2 を返す asin (double x) . 逆正弦関数 0 からを返す acos(double x) : 逆余弦関数 ーな / 2 から 2 を返す atan(double x) : 逆正接関数 ーからを返す atan2 (dou ble y, double x) : 逆正接関数 (atan (y/x) を計算する ) 自然対数 常用対数 平方根 絶対値 x を仮数部と指数部に分け , 指数部を * p に代入し , 仮数部を返す f 「 exp の逆変換 ldexp(double x, int * p) : Fig. 1 ca 厄の使用例 ・・計算結果の表示形式を与える asin(sin(O. 5)) 入力した式 , 関数計算 ・・計算結果 0.5 x = sqrt(y = 0.81 ) ・ ・・代入を含む式 0.9 p は直前の計算結果を表す 0.9 log (E) 1 double List 3 CGROUP GROUP TEXT TEXT CSEG MOVSX: . ;copy AX: SI t0 BX:DI bY CX bytes PUSH DS ES PUSH push di pus h MOV DS, MOV ES, BX CLD REP MOVSB POP S 1 POP d i POP E S POP DS RETX 1 0 3 -4 - -0 6 7 8 9 0 、よりな 00 4 0 6 7

8. 月刊 C MAGAZINE 1992年4月号

特集 しかし , まったく空白と区別のつかない こともあります。このリストが , タブがス ペース 4 個間隔になるという仮定て、書かれた ソースだとしましよう。タブがスペース 8 個 間隔になるような表示て、これを見ると , Li st 15 のようになるて、しよう。 これは , 単にインデント幅がスペース 4 個 から 8 個になっただけて、すが , これならあま り気にならないかもしれません。しかし , フフまくいくとはかぎりません。た とえば , 変数の定義の箇所て、 , 変数名を揃 えたくなる人は多いようて、す。また , コメ ントの始まる位置も揃えたくなるようて、す。 Char int POS タブをスペース 4 個間隔のつもりて、書いて いる人がこのように書いた場合 , char の後 にあるのはタブが 1 個 , int の後にあるのはタ プが 2 個となります。 int というのは 3 文字な のて、 , タブが 1 個て、は次のようになってしま います。 Char int pos 同じリストをタブがスペース 8 個間隔の人 が見ると , 次のリストのようになりますが , これはちょっと見にくいのて、す。 Char int static int lcount int static int lcount Char POS 多分 , 次のように書きたくなるはずて、す。 POS わざわざすらせて合わせるべきて、しようか。 数を追加したくなった場合 , ほかの変数も static unsigned long の変 て、は , さらに Char int static int POS lcount static unsigned long wcount 0 この後て , やつばり lcount や wcount は , 外部変数にして , ソースプログラムの頭に 書こうと思い , 2 行削った後が , cha int POS char int POS それて、は , タブがスペース何個に相当す るかにかかわらず , あまり見苦しくなく表 示されるように書くにはどうすればよいて、 しようか。 簡単て、す。タブを使わなければいいのて す。 リストの空白を , タブて、はなく空白て、表 現すれば解決します。 ところが , この場合も , いったい空白を いくつ置けばよいのかが問題になります。 たとえば , 次のような 1 行を追加したくなっ たら , どうしましようか。 static int lcount 変数名の書き始める位置にこだわってい る人なら , 多分次のように書くのは見苦し いと思うて、しよう。 というのは , さすがにみつともないのて , また左につめるのて、しようか。 こういう作 業はやってられない というのが正直なと ころだと思いますが , ぶつぶついいながら , ちゃんと揃える人も多いかもしれません。 あるいは , この程度なら後て、揃えるための ソフトがあるかもしれないし , そういう機 能を備えたり , マクロて、処理て、きるように したエデイタがあるかもしれません。 しかし , 私はこういう手間に神経質にな るのは不本意て、はないかと考え , 長年の研 究の結果 , ついに次のように書くことを結 論するに至りました。空白はひとって十分。 べつに見にくくもなんともないと思い込む のが秘訣てす。と書きましたが , 改めてこ うして見てみると , そんなに見やすくない 書くことになります。という余談はともか ように書いてあるのて , 自然にこのように R の書き方を真似していると , 最初からこの ちなみに , 別に長年研究しなくても , K& static unsigned long wcount static intlcount int pos char *S , ような気もします。 0 C プログンの秘 く , なぜ前記の表現があまり見やすい気が しないのか考えてみますと , どうも , static unsigend long という前書きがあまりに長すぎて圧倒され てしまい , 肝心の変数名があまり目立たな いからのようてす。このような場合には , typedef unsigned long ULONG とて、もしておけば , 次のようになります。 char *S ; int pos 特集 C プログラミングの秘訣 59 わかる程度に , しかし目をあちこち動かさ れません。インデントの幅は , ばっと見て ぎることになり , 疲労の原因となるかもし デント幅が広すぎると , 目が左右に動きす 苦しくなってしまうからてす。また , イン ってしまい , ついに折り返して , かなり見 ントを行うと , 書く内容がどんどん右に寄 なぜならスペース 8 個を 1 段としてインデ 多いものてす。 スペース 4 個分の間隔としたい , という人も それて、も , C のプログラムのインデントは , ーディングする人が多くなりがちて、すが , そのため , タブをスペース 8 個と考えてコ ませんが ) 通常そのようになっています。 ど , ( 何か技を使えば変更てきるのかもしれ MS-DOS の type コマンドを使ったときな は , かなり頻繁にあるようて、す。たとえば 実際 , タブがスペース 8 個とみなされること 8 個として書かれているものとみなします。 ただし , 今度は , これがタブをスペース ましよう。 List 16 を見てください ンデントがもっとひどくなる例を考えてみ に対する文字数が異なることによって , イ またまた話題を元に戻しましよう。タブ た。 りが揃うようにタブを使って書いていまし 最近のことて、 , かなり長い間 , 変数の始ま 身 , このように書くようになったのがつい 異論のある人も多いて、しよう。実は , 私自 によって意見の分かれるところて、すから , ただ , このあたりの感覚は , かなり個人差 この程度なら , あまり変に見えません。 0 static ULONG wcount static int lcount

9. 月刊 C MAGAZINE 1992年4月号

は「 a に b の値を代入する」という意味になっ x = ( 70 * a ) 十 ( 21 * b ) + ( ( 15 * c ) % 105 ) ; 答えを小数点以下まて、求める方法は次号 てしまいます。比較は「 = = 」 , 代入は「 = 」 の計算になってしまいます。 以降て、詳しく述べます ( 数を 4.0 のようにわ と覚えてください ざと小数点をつけて書き , printf の「 %d 」を 条件判断 if は , 「そうて、なければ」という意味の else 「 % g 」にします ) 。 ( 工ルス ) と組み合わせて , Fig. 6 のようにも 使えます。これは , 「もし x < 5 なら命令 1 と プログラムによっては , 単純な計算て、は 力してみよう 命令 2 を実行し , そうてなければ ( つまり x と 片づかず , 場合分けを要することがありま 5 なら ) 命令 3 と命令 4 を実行せよ」という意味 int 型の変数 x を作る命令は int x ; て、 , そ す。 てす。 場合分けのための命令は if ( イフ ) て、す。 れにたとえば 5 を代入する命令は x = 5 ; て、し List 6 は , 年月日を入力すると曜日を出力 if はたとえば Fig. 5 ( a ) のような形て使わ するものて、す ( ℃言語による最新アルゴリ れます。これは , 「もし x が 5 より小さいなら 代入する数値が最初からわかっていない ズム事典』 288 頁のものを簡単にしたもの ) 。 命令 1 と命令 2 を実行せよ」という意味て、す。 ときは , x=5 ; のような代入文の代わりに 曜日を求める計算式の根拠を考える必要は 中力ッコ { } の中には , いくって、も命令 ありません。 if の使い方だけをよく観察して が書けます。中力ッコの中にまた別の if があ と書きます (BASIC の「 INPUT X 」 , Pasca ってもかまいません。中力ッコの中に命令 ください 1 の「 read ( x ) 」に相当します ) 。オマジナイの このプログラムて、は , int 型の変数名とし がひとっしかないなら , 中力ッコを省略し ように覚え込んて、しまいましよう。 て year, month, day, dayofweek のような て Fig. 5 (b) のように書いてもかまいませ List 5 は℃言語による最新アルゴリズム 長い名前を使っています。今まては x とか a 事典』 226 頁の「百五減算」という簡単なパズ ん。 のような短い名前を使ってきましたが , 長 if の次のカッコ ( ) の中には TabIe 1 のよう ルて、す。 い名前を使うと個々の変数の意味がはっき な条件式が入ります。 プログラムの実行が りするのて読みやすくなります。 = b 」は「 a = b 」と厳密 この最初の「 a このプログラムには , if 以外に , 変数の値 に区別しなければなりません。「 a = b 」て、 のところまて、くると , 入力待ちの状態にな ります ( 言葉て、説明するより , やってみたほ 百五減算 ( 105. c ) うが簡単て、す ) 。そこて、たとえば、、 2 クと打 ち込めば , a に 2 が代入されます。 scanf て、は変数名の頭に必ず「 & 」 ( アンド ) 印をつけることが必要て、す。たとえば & a を a にしてコンパイルすると , LSI C ー 86 コンパ イラは Fig. 4 のような警告を発します ( プロ グラムによっては警告が出ません ) 。 それて、も強引に実行すると , 誤動作ある いは暴走します。 t 算式 x = ( 70 * a 十 21 * b 十 15 * c ) % 105 ; の中の「 % 」は余りを求める記号て、す。つま り , 70Xa 十 21Xb 十 15Xc の答えを 105 て、割 った余りを x に代入します。 このようにカッコ ( ) て囲んだ部分を先に 計算するのも通常の計算のルールと同じて、 す。カッコは何重になってもかまいません。 余りの計算「 % 」はかけ算「 * 」や割り算「 / 」 と同じ優先順位て、計算されるのて、 , カッコ がないと List 1 : / * 105. c * / ・・注釈 2 : #include く stdiO. h> ・・・入出力の準備 ・・・以下がプログラムの主要部分 3 : main() ・・・ int 型の変数 a , b, ら x を用意 int a, b, c, x; 5 : 6 : printf ( " 1 から 100 までの整数を 1 つ考えてください。 *n"); 7 : printf ( " それを 3 で割った余り ? " ) ; 8 : scanf("Xd ” , &a); 9 : printf ( " それを 5 で割った余り ? " ) ; 10 : scanf( ” Xd ” , (b) ; 11 : printf ( " それを 7 で割った余り ? " ) : 12 : scanf("Xd ” , (c) : 13 : = ( 70 * a + 21 * b + 15 * c) % 105 ; 14 : printf ( " あなたの考えた数は Xd でしよう ! \ n " , x); return 0 ; 【注意】オペレーティングシステムによっては , p 「 in ぜの "... " の最後に「 \ n 」がない場合は , その「 p 「 in 廿 (... ) ; 」の直後に「用 ush ( stdout ) ; 」という命令 ( 出力バッフアに溜まっ ているものを吐き出す命令 ) が必要です。 ・ a の値をキーポードから入力 ・ b の値をキーポードから入力 ・・・ c の値をキーポードから入力 ・ ( 70Xa 十 21Xb 十 15Xc ) を 105 で割った余り を x に代入 一三 戸 0 叮ー Fig. 4 scanf の変数名に & 印をつけないときの警告 105. c 9 : Warning . a' used before set 104 C MAGAZINE 1992 4

10. 月刊 C MAGAZINE 1992年4月号

実力養成講産 ~ ートルプ C + + いよいよ最終回です。 1 年間の連載で C 十十とは , こんなものなんだ あと感じていただけたでしようか ? 今回 , 理論編では , 生産性を 向上させるためのライプラリの解説と 0 ナナの利点を ! 実践編で は , 神経衰弱ゲームの作成をとおして C 十十とは何か ? を探って ームえるの随を楽しみー 、キます両 理論編 List クラスをひとつ用いたプログラム 木戸研ー / 龍崎昌平 「 = - 。矛なクラスライプラリ まず , 実際のクラスライプラリを例に 再利用について考えましよう。 ライプラリとは , 特定のプログラムを再 利用が可能て、あるように汎用化したものて、 す。 C 言語の世界て、は , 標準関数などをコン パイルしたオプジェクトプログラム群をラ イプラリと呼びます。 C 十十は , 同じ変数を 使う関数群をクラスを用いて集めることが てきます。ゆえに , C 十十においては , 関数 て、はなく , クラスをライプラリ化すること が可能となります。つまり C 言語のライプラ リとは , 関数を再利用するものて、あり , C 十十 のクラスライプラリとは , 変数と関数の両 方を再利用することを可能にするものとい えるて、しよう。 C 十十を用いて , プログラムの再利用を実 現することを考えてみましよう。 List 1 は , older と同じ機能を持ったクラスが必要にな クラスをひとっ用いたプログラムて、す。ク クラス変数 anArray を宣言し , n において , ったと仮定します。 ラス ArrayHolder は , 内部変数として配列 その関数 ( メンバ関数 at ) の呼び出しを行って その場合 , List 1 のクラス定義の部分だけ をひとつ持ち , 指定する配列要素の値を返 います。 ヘッダファイル , arrayholder. h (List 2 ) と さて , 別のプログラムて , クラス ArrayH す関数 at ( ) を持っています。そして , mai ェ・ #lnclude く stream. h> 2 : class ArrayHolder 3 : private: arrayC100] ; int 5 : public: 6 : 7 : int 9 : main() 10 : { 11 : i nt ans : 12 : ArrayHOIder anArray; 13 : ans=anArray. at(l) : 14 : cout くく ans; at(int n) { return array[n] : List arrayholder. h 1 : class ArrayHoIder ( 2 : private: arrayC100] : 3 : int 4 : public: 6 : i nt at(int n) ( return array[n] : 106 C MAGAZINE 1 2 4