工ル・エス・アイジャパン 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
特集℃プログラミンクの秘 語は , C のプログラムて、あっても使わない 界からは当然そんなことは知ったことて、は うわけて、す。 とをおすすめします。 ないのて、す。 ほかに , よく使われる伝統的な意味を持 たとえば , 学校の成績処理プログラムを このような , 自分の世界以外て、使われて つ変数を示しておきましよう。 書きたい人は , 次のような構造体を作りた いる名前というのは , 案外無頓着なものだ int C くなるかもしれません。 し , 実際 , それて、問題になることも極めて 文字を格納する使い捨ての変数て、す。 struct student { 希て、すが , それて、も知識として持っている れを char とする人がよくいますが , 伝統的 名前があれば , 考慮するに越したことはな に int て、す。また , int て、受けないとおかしく int grade int Class , いと思います。 なることもあります ogetc などはマニュアル ただし , これらの関数名を伝統的に使わ int number を見ればわかるように , int の値を戻します れている関数と同じ機能を模倣するために char *name , から , 当然 int て、受けなければなりません。 使う場合は別て、す。かえって変な名前をつ char *S , この構造体の欠点は , class という名前を けるとイメージがわかないからて、す。この 作業用の , 文字列へのポインタとして使 使っていることて、す。将来 C 十十に移植しよ ような場合て、も , printf て、はなく my printf います。 string の頭文字を連想させるためて、 うとした人が , びつくりするかもしれませ という関数名にしておく手があります。 ん。悲惨なことにならないことを祈ります。 C 言語からほかの言語へのプログラムを移植 これらは , 使い捨ての変数として使われ する機会は , 神経質になるほどのものて、は ます。 for て、ループさせる場合のカウンタに ないかもしれませんが , 一応 , C 十十への移 次のリストを見てください。少し C て、プロ よく使われます。これらにかぎらず , 1 文字 植というのは , もっともありそうなことて、 グラムを書いたことのある人が見ると , 「間 の変数は , おもに使い捨ての一時変数とし すから , C 十十の予約語は避けておくのがよ 違っているぞ」と指摘されるかもしれませ て使われるものと思えば , たいてい間違い いて、しよう。 ありません。 ん。 もうひとつの , 使ってはならない名前の void main(int argv, char *argc [ ] ) int n 同にく使 0 、捨、 0 変数て、す , 00000 , を 指針。 ANSI 以外の処理系における慣習的な 関数名は , ほかの用途に使わないほうがい 連想させるのて、 , 個数を意味することが多 いて、しよう。ただ , 私もそうて、すが , 多く いようて、す。 のプログラマは自分のかぎられた世界に閉 long に じこもることが多く , ほかの世界が見えな 使い捨ての変数て、も , 1 は 1 。 ng の変数とし くなってしまうことがしばしばあります。 て使われることが多いようて、す。 しかし , このプログラムは文法的には何 さすがに printf や fopen という名前を , 自分 も間違ってはいないのて、 , コンパイルすれ int len て、定義したまったく別の関数につけること 長さて、す。何の長さかは , 場合によりま ば , 予期したとおりに動作します。間違っ はありません。 す。 long のことがあるかもしれません。 10n ているのは , プログラムて、はなく , main の しかし , UNIX の世界しか知らない人は , g なら llen と書きたくなるところてすが。 引数に argv, argc という順序て名前をつけ findfirst という名前をまったく独自の関数の char buf [ ] るという感性て、す。この種の名前は , 伝統 名前として使ってしまうかもしれないのて、 作業用の文字列を格納するためのバッフ 的に命名されていて , プログラマが勝手に す。なぜなら ,DOS の世界に findfirst という アとして使われます。 buffer の後半分を略し 変えるのは望ましくありません。そういう 関数があるということを知らないからて、す。 意味て、はこのプログラムは確かに間違って たものて、しよう。 何か最初の要素を検索するような関数に いるわけて、す。 char *src , findfirst という名前をつけたくなるのは自然 伝統的に使われる名前は , て、きるだけ先 char *dst ; な発想なのてす。 達に従うのが得策て、す。 src は source, dst は destination を意味して 逆の例てすが , 昔 LHarc を UNIX に移植し argc, argv はそれぞれ関数 main に渡され います。文字列をコピーするような場合に , たとき , link という関数が独自に定義されて る引数て , コマンドラインのパラメータの src から dst に向かってコヒ。ーすることになり いたため , とんてもない目にあった経験が ます。 数と , 各パラメータの文字列へのポインタ ありました olink という関数があることは U を順に格納した配列を意味するのが伝統て FILE *fp , NIX の世界ては常識なのてすが , DOS の世 ファイルポインタとして使われます。 fil すから , 上のように書いたら目茶苦茶とい 65 特集 C プログラミングの秘訣 す。 int i, イ的に使われる名前 while (——argv > 0 ) { puts(*argc 十十 ) ;
LANGIJAGE 真理関数論理 た MN) スクラゝチノヾッド A Scratchpad 館 T 頑ト FunctionaILogic Gianfranco Boggio-Togna/ 岩谷宏訳 (COMPUT R LANGUAGE, Dec. 円 9 1) 雑な論名まどんなプログラマをも混乱させる。真理 関数のためのスクラッチバッドは最高にややこしい問題 で解明を支援する ALGORITHMS ーま新第 0 馬 もた OMP リ R IANGIJ, Å GE A [ GO 翩期 5 5 P ・ BY ・ 5 種 P 提携記事 MPLEX ーに Gender 釦 印圓 R 胤ー 理論を完成させています。 プログラマは , 論理式ないしプーリアン ばよいのて、す。 真理関数論理は , 論理の基礎的な部分て、 ーっの論理式は , それの項 ( 複数 ) の真理 式をよく使います。条件文を使わないて、 , あり , その他の部分はそれの上に構築され 値の真理関数て、す。 何か実用性のあるプログラムを書くことは , ほとんど不可能て、す。条件文て、は , if の後に プログラミング言語と , それの論理式に ます。 何らかの形の論理プログラミングに手を 論理式が続きます。 は , 30 年あまりの歴史があります。記号論 出してみたい人は , 真理関数論理からスタ その論理式は , ふつうはごく単純て、す。 理にはもっと長い歴史があり , その一分野 x=0 〔 Pascal 記法 , C て、は x = = 0 〕とか i< ートしなければなりません。 て、ある真理関数論理 ( ないし命題論理 ) は , しかし , 論理プログラミングに関心がな コンヒ。ュータやプログラミンク言語が登場 n といった単一の項が , プログラムの変数 くても , 真理関数論理の十分な理解がどん するよりもずっと前に , 真理関数に関する と , 他の変数ないし定数との関係を記述し ます。その関係が成り立てば , その式は真 TabIe 1 演算子のアクションは表で定義される になります。 オペランド ときには , 複数の条件の組み合わせをチ ェックしなければならない場合があります。 どのプログラミング言語も , 複雑な式を構 築するために not , and, or という三つの演 算子を提供しています。これらの演算子の アクションは , TabIe 1 に示すような表て、定 義て、き , オペランドの値の組み合わせと式 の値を対比させられます。 これらの表は , 項の形式や意味は何も表 現していません。唯一かんじんなのは , 項 が真か偽かということて、す。そこて、このよ うな表を , 真理値表と呼びます。 実際 , 論理式というものの特徴は , 真か 偽かのどちらか ( = 真理値 ) にしか評価され という点にあるのて、す。論理式を評 価するためには , 各項の真理値さえわかれ not オペランド オペランド land オペランド 2 真 オペランド 10 「オペランド 2 真 オペランド 2 真 真 オペランド 2 真 偽 真 オペランド 1 真 オペランド 1 真 真 22 C MAGAZINE 1992 4
List 4 : 5 : 6 : 7 : List Cha 「 A 「「 ayHo 旧 e 「クラスの派生 arrayholder. ” cout くく ans : ans=anArray. at(2); ArrayHo 1 der anArray : int ans : 2 : main() 1 : #include プログラムの再利用の例 char func(int Ⅱ ) ( return(charArrayCn]) : } publ ic: char charArrayC100]; pr i vate : class CharArrayHoIder:pubI ic ArrayHolder { arrayho 1 der. h ” #include して独立させ , List 3 のようにインクルード することて , このクラス ArrayHolder は , 再利用が可能になります。 これは , クラスをそのまま完結したもの として使っており , ューザプログラムては , まったく手を加えていません。つまり , 閉 じた再利用を行っているということになり ます ( 閉じた再利用については前号を参照 ) 。 C 十十におけるクラスとは , C 言語の関数 をクラスに拡張したプログラム群です。よ って , このように C 言語のライプラリと同様 の再利用が可能てす。 しかしこれては , C 十十やクラスをあえて 用いる必要はありません。この例ては , ク ラス ArrayHolder を用いているというより も , 関数 at( ) を使っているという感覚て す。いうなれば , こうした閉じた再利用は , C 十十のライプラリの使い方としては , 極め てつまらないものてす。 C 十十のクラスライプラリの利点は , この 閉じた再利用がてきるということだけては ありません。 C 十十は , クラスを用いて , 変 数の再利用もてきる , つまり開いた再利用 が容易にてきるのてす。 main() Char ans; CharArraYHOIder anArray; ans =anArray. func ( 1 ) ; C 十十のクラスは , 変数 ( = メンバ変数 ) と , その変数に対する操作関数 ( = メンバ関 数 ) を持ちます。クラスにおいて , もっとも 重要な機能は , クラスを派生して既存の変 数と関数に変数や関数を追加し , 新しいク ラスを定義てきるという機能てす。こうし て作られるクラスの連鎖をクラス階層と呼 びます。クラス階層においては , いくらク ラスを派生しても , 既存のクラス群には , まったく影響がありません。このクラスの 派生によって , 開いた再利用が可能となる のてす 0List 4 を見てください。これは , 先 ほどの ArrayHolder を基本クラスにして , メンバ変数として char の配列を持った , Ch arArrayHolder というクラスを派生させて います。そのために , 基本クラスの定義が 行われているヘッダファイルをインクルー ドしています。 ′クフスライプラリの実際 さてここて , 開発の現場て使われている クラスライプラリを例にして , クラスを用 いた再利用の実際について考えてみましよ スタートアップ C 十十 最終回 こて取り上げるのは , おもにワーク 義ファイルは , ヘッダファイル ( * * * . h) る必要があります。そこて , このクラス定 ように , このファイルがインクルードされ ログラムから再利用するためには , 前述の こて定義したクラスをユーザ作成のプ す。 り , 1 クラスが 1 ファイルに定義されていま れるクラスの数と同数分存在します。つま きます。これは , クラスライプラリに含ま フェイスを定義したものと考えることがて、 義したものて , オプジェクトの外部インタ 変数と , その変数に対する操作手続きを定 向の立場からみると , オプジェクトの内部 成されています。これは , オプジェクト指 トタイプ宣言したメンバ関数群によって構 体的には , クラスの内部変数の宣言とプロ ラリを構成するクラスが定義されます。具 まず , クラス定義ファイルては , ライプ 成り立っています。 ァイル ( * * * . o) の , 3 種類のファイルから ル ( * * * . c) , オプジェクトプログラムフ ァイル ( * * *. h) , メンバ関数定義ファイ このクラスライプラリは , クラス定義フ なります。 加える開いた再利用も , 可能ということに 用する閉じた再利用も , 派生クラスをつけ す。もともとは , UNIX のユーザ団体て、あ そのクラス階層の一部を Fig. 1 に示しま くつかの拡張を行ったものてす。 SmalltaIk ライクなクラスライプラリに ted Program Support (OOPS) と呼ばれる る , USENIX て、配布していた Object-Orien す。もともとは , Unix のユーザ団体て、あ SBN 0471 92346 X)<, 解説されていま ect-Oriented Programming in C 十十』 (I rlen らによる「 Data Abstraction and Obj す。その詳細については , 作者の K. E. Go ealth の略て , フリーソフトウェア扱いて、 変わった名前は , NationaI lnstitute of H 用いた経験のあるものて、す。 NIHCL という プラリて、 , 筆者らが実際の開発て、しばしば プラリのひとってある , NIHCL クラスライ ステーションて使われている C 十十用のライ として作成されています。 スタートアップ C 十十 107
なプログラマにとっても欠かせない カッコの必要性を減らすために , 連結記 p 三 q という形の式は , 実質同値式 (mater 思いになるて、しよう。 号の優先順が定義されています。否定は合 ial biconditional, 実質双条件式 ) と呼ばれ , 私はプログラミングの入門コースを教え 接に優先し , そして合接は離接に優先しま (pDq)A(qDp) とも書けます。これらの新 ている教師て、すが , 非常に優秀な生徒も含 す。そこて、 , カッコなして、書かれた式が最 たな連結記号は , 不可欠てはありません。 めて , とても多くの生徒が , ごく簡単な論 初に解釈されます。 真理値表から分かるように , PDq は .pvq 理式の操作に手間取っている様子を見て , 真理関数の式には , 他にも二つの重要な と置き換えることがて、き , p 三 q は pqv .(p 不思議な気持ちになることがしょっちゅう 連結記号が使われます。それらの記号は , q) と置き換えられます。三つの基本演算子 あります。て、も , 複雑な式になると , 経験 つ ( →とも書く ) と三て、す。これらには通常 , (not, and, or ) て、すら , 三つとも全部は必 豊富なプログラマて、さえ , ドジを犯すこと △と同じ優先順が与えられ , その真理値表は 要ありません。 not, and と or のどちらかだ がありますが。 Table 2 のとおりて、す。 pnq という式て、は , けて、 , あらゆる式を表現て、きることが証明 p が前件 (antecedent) , q 力す後件 (consequen されています。たったーっの演算子て、 , ど 真理関数式 t) と呼ばれます。こういう式全体のことを , んな式て、も表現て、きる , という演算子を定 実質条件式 (material conditional) と呼び 義することすら可能て、す ( シェファーの筆法 本稿は , 真理関数論理の基本概念への入 ます。 〔 NAND 〕など ) 。 門編て、す。付随して提供するプログラム QU 実質的 , という形容詞がなぜ式の名前に 冗長な連結記号は , 実用的に便利だから INE を使うと , 教科書に載っている , 紙と鉛 使われているのか , 不思議に思われるかも 使われているのて、あり , 複雑な式の扱いを 筆を使って解く無味乾燥な練習間題よりは , しれません。この真理関数式と , 日常言語 大幅に単純化してくれます。 面白くそして効率的に この主題を探究て、 の if... then 文は , 明らかに関係はあります 真理関数式の場合は , その各項に何らか きるて、しよう。 が , しかし区別して考える必要があります。 の真理値を代入したときの式の値は , 真理 論理式 (logical expression) 〃という言葉 その区別をしないと , 不合理が生じます。 値表の規則を当てはめれば分かります。し は , 真理関数論理 (truth-functional logic) 「 if ロンドンがフランスの首都 , then 2 十 2 = かしプログラマは論理式に対して , プログ の分野て、は使われません。代わりに , 式 ( fo 4 」という文と , 「 if ロンドンがフランスの首 ラムの実行を手作業て、辿りながら , 真・偽 rmula(s)) という言葉を使います。式は論理 都 , then 2 十 2 = 5 」という文は , 実質条件式 の結果を判定しようとします。て、も , われ 式と似ていますが , しかしその項は , 不特 のインスタンスとして解釈したときには , われプログラマも , もっと一般的な問題を 定の命題を表す一つの文字て、す ( 代数と同じ どちらも真て、す。しかし日常言語の条件文 考えてもよいのて、はないて、しようか。真理 て、 , 文字は不特定の値を表します ) 。文字 としては , どちらもナンセンスて、す。 関数式は , その項の真理値のあらゆる可能 は , ありうる値が真と偽の二つて、あるとこ 実質条件式のこの定義は , 論理の展開に な組み合わせに対して , いかなる値をとる ろの , 変数を表します。それらを , 特別な とって便利て、あることが証明されています。 か ? 記号を使う連結記号 ( 論理式の演算子に相当 ) 日常言語の文と , 真理関数式との関係は , 三つの可能性が存在します。 て、もって結び付けます。 難解て、複雑な哲学的問題て、あるため , ・その式はその項にどんな真理値を代入し 否定 ( not ) は , 横線や + て、表します。単一 て、は論じません。良い参考文献として , W. ても真に評価される ( その単純な例が pV の変数に対して使うときは , 文字の上に V. O. Quine の Method of Logic [ 1 ] や , P. p や PDP)0 このような式は , 妥当て、ある の記号を書きます〔文字が横線という、、帽子〃 F. Strawson の lntroduction to Logic The (valid) とか , 同語反復 (tautology, トー をかぶったような形になる。項の前にと ory ②があります。 トロジー ) て、ある , と呼ばれます ( tautolo 書く書き方もある〕。合接 ( 論理積 ) を表す記 Table 2 真理関数の連結記号 号は△て、すが , しかし通常それは , 代数て、積 を表現するときのように項を並べて書いて 表します。最後に離接 ( 論理和 ) て、すが , れは V て、表します。曖昧さを防ぐためには , カッコを使います。カッコがないとたとえ ば , pVqAr は pv (qAr) とも (pvq) Ar とも解 釈されます。 とは 真真偽偽 真偽真偽 真真偽偽 PDq 真 真 真 真偽真偽 P q 三真偽偽真 真理関数論理のためのスクラッチバッド 23
epointer だから , fp て、す。ただし , しばし ばファイルを扱うプログラムを書く場合に は , ふたつ以上のファイルを扱いたくなり ますから , fp だけを使っていては混乱するか もしれません。 fp in, fp out のような書き 方はよく見かけます。 int fd ; ファイルディスクリプタの意味て、しよう。 int * p , 使い捨てのポインタとして pointer を連想 させる p を使います。これがたとえば long へ のポインタだと , lp となることが多いようて す。 Size t Size , 文字どおりサイズて、す。何のサイズかと いうと , おもに malloc のようにメモリを獲 得する関数への引数として使われますが , それ以外の用途にもよく使われるようてす。 int status , ステータス , すなわち状態て、すが , 何の 状態かというと , しばしば関数の戻す値 , もしくは exit の引数として使われます。 int temp , 次に問題になるのは , て、は , 自分が勝手 述べました。 のように使うのがよい」という方針に関して 自分勝手に使わないほうがよい」 , または「こ というわけて , 今まて、 , 「こういう名前は 印象的に登場するこど あるのて , 参考にするとよいと思います。 と , 引数の説明として使われている名前が このほかに , C の関数マニュアルを見る て , しばしば用いられます。 ムの中て、はなく , 説明のための関数名とし これらの名前は , 実際のソースプログラ intfoo(), bar() ; これは明らかに一時変数て、しよう。 66 C MAGAZINE 1992 4 単て、すが , 「 ~ するのがよい」というのは説 一般に「 ~ してはいけない」というのは簡 るのか , ということて、す。 に定義したい名前について , 何か指針があ 明困難になりがちて、す。あえて , どのよう な名前をつけるべきかという指針について 考えてみたいと思います。 言て、説明すれば , 「わかりやすい名前を つける」が大原則て、す。これだけて、も本質的 に理解していれば , あとは感性に正直に名 前をつけても , 相当変な人て、ないかぎり , 何も問題になりません。ただ , 驚いた に , わかりやすい名前にしようとさえ夢に も思わない人が結構いるように思えるのて、 すが。もうひとつは驚くには値しません。 どうすればわかりやすい名前になるのか , 理解て、きない場合て、す。 て、は , いったいどのような名前をつける とわかりやすいのて、しようか ? これは , 経験を積むに従って , 自然に身についてく るものだと思います。 まず考えておきたいのは , その名前を見 ただけて、 , 働きが一目瞭然て、あることて、す。 xc という名前が何を意味するのか , わかる 人はほとんどいないて、しよう。これが , tra nsfer count という名前だったら , 「何か転送 するとき回数が入っているのだな」程度は想 像て、きるのて、す。よくいわれることて、すが , こて、重要なのは , その意味を的確に表現 する名前を用いるということて、す。これは もっともなことてあり , 探せば多くの本に 書いてあるはずて、す。 フィンローダ流に関しては , もうひとつ 重要なことて、 , かっ , ほかの本にはあまり 書かれていないことがあります。それは , 「印象的な名前をつける」ということて、す。 ばっと一目て、気に入ってしまうような名前 がついたら成功て、す。なぜそれが本に書か れていないかというと , じゃあどうすれば 印象的な名前がつけられるんだ , といわれ たとき , そんなことは言葉て、説明がて、きな いからて、す。 名前き方 現状て、は , 日本語の名前が使える C コンパ イラは , あまり見かけないし , ANSI の規格 どおりなら , 当然日本語の変数名など考慮 されているわけがないから , いわゆるメジ ャーなコンパイラについては , 英数のみ使 えると考えておきます。 まず , 英単語を名前に使うとして , 省略 するか , 省略しないかという選択がありま す。例を見るのが手つ取り早いて、しよう。 char * file name ; / * 省略しない * / char *fn / * 省略する * / 省略しないメリットは , 意味を誤解する 確率が小さくなることて、す。 fn と書くと関数 名のことかと誤解するかもしれませんが , file name を見て関数名かと思う人はまずい ませんし , これを見た人は必ずファイル名 て、あることを理解て、きます。 て、は , 省略するメリットは何て、しようか。 ひとつは , あまりにもしばしば使われる変 数に長い名前をつけてしまうと , 入力する のがたいへんだということて、す。 ある程度長い名前になると , 開発環境に よっては cut&paste のような方法て、 , 文字列 コヒ。ーがて、きるのて、 , そのほうが間違いが 少なくなります。長い名前はタイプ時に間 違いがちなのて、嫌だという人がいますが , これはある意味て、危険て、す。タイプ時に間 違う確率は , 何文字あたり 1 回というものて、 あって , 短い変数て、も間違えるときは間違 えるものて、す。間違えたとき , どの程度の 影響があるかということも検討しておくべ きて、す。短い変数をいくつも使っていると , タイプし間違えたとき , 偶然別の変数にな ってしまうことがあります。この原因によ るバグは , 一度コンパイルに通ってしまう となかなか発見て、きません。長い名前の場 合 , 間違えてタイプしたら , そんな変数は ないとコンパイル時にはじかれる確率が高 くなり , その意味て、は安全かもしれません。 しかし , 長い名前にもデメリットがあり ます。あまり長い名前だと , 肝心の処理の 流れを理解するための思考を妨げる危険も あります。名前を追いかけて最後まて、読ん て、 , ああこれはあの変数だな , と思ったと きは , 今 while のループ条件を調べていたの か , if の判断の途中だったのか忘れてしまう かもしれません。という例はさすがに大袈
メンバ関数ファイルは , クラスが持つメ ンバ関数群を定義するものて、 , ファイルの 先頭て必ずそのクラスが定義されているフ ァイルをインクルードしています。実際に は , 各クラスの定義部分て、 , プロトタイプ 宣言されているメンバ関数群の実体を持っ ています。 このファイルの実体は 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
ば 24 行という一定の行数て、書く努力をする えているときは , 最初のほうて、どんな処理 これに似たことて、すが , 非常に長いひと よりは , 自然な流れになるように関数を作 をしていたのか , すっかり忘れてしまうか つの関数を作るのて、はなく , ある程度の短 るほうがずっと得て、す。 らて、す。 い関数をいくつも作って呼び出すほうがよ また , あまり関数を短くすると , 必然的 また , 行数が多すぎると , それにつれて いといわれます。 に関数の数が増えることになります。ある 使う変数の数も増え , 間違って一時変数を て、は , ファイルを分割するにあたって , 関数の処理を理解するには , その関数が呼 どのように関数を配分すればいいのて、しょ 二重に使ってしまうという , あり得ないよ び出している関数の処理を理解しておかな うか。これは非常に難しい問題て、す。あま うなバグが入ることもあります。これも , ければなりません。 どこて、何をしているのか , 全体的に把握す り分けすぎると , かえってわかりにくくな 呼び出している関数が何だったか確認し るのが困難になるための副作用だと考えて ってしまうからて、す。 ているうちに , 呼び出している元の関数て、 原則は , 関連ある関数 , 変数をひとつの よいて、しよう。 何をやっていたのか忘れてしまうようて、は , したがって , 当たり前のようてすが , 原 ファイルにまとめるという単純なものて、す。 元も子もありません。 ところが , 実際に行うとなると , これがな 則として , 行数を少なくすることが , わか List 6 の処理の内容を大雑把に把握するの かなか難しいのて、す。なぜならば , プログ りやすさを増す秘訣て、す。ただし , ここて、 は簡単て、す。なお , コメントのうち , 最後 ラムの中にある関数 , 変数というのは , 完 いっている行数というのは , 処理の数を指 の「ファイルを閉じる」というのは明らかに しているのて、あり , 単に 1 行にいくつも処理 全に関係あるものと関係ないものに分かれ ムダて、あり , close file という名の関数がフ を書いたのて、は , ほとんど意味がありません。 る場合もありますが , 多少関係あるとか , ァイルを閉じることは , 99 % の人なら瞬時 ほとんど関係ないが , 無関係て、もない , なかには , 関数の長さは 1 画面に収めるよ と に想像て、きます ( たとえファイルを閉じると いった瞹昧なものもあるからて、す。 うに , つまり , 24 行以内て、書きなさいとい いうことが , どのような処理か理解してい う人もいます。何が「つまり」なのかわかり 初心者のうちは , それほど大きなプログ なくとも ) 。しかし , open file の中て、どのよ ラムを作ることもないと思いますから , あ ませんが。ワークステーションなどて、は 1 画 うな処理が行われているか , 確実に把握す まり分割に気を遣うこともないて、しよう。 面に 40 行程度表示て、きるものがありますが , ることはて、きません。 List 7 のように書けば 分けることばかり考えるよりは , ほかのこ その場合は 40 行まて、書いていいのか , など 処理の内容は明確になります。 とに頭を使ったほうがいいと思います。 と悩む必要はありません。 すて、に , 思考の順序に従って書くという [ 注 ] 奧義を紹介しました。これに従っていれば , ( 1 ) アルジャーノン・ゴードン効果という。 おおむね前後の処理の結び付きがもっとも ②参考文献 [ 1 ] , [ 2 ] 参照。 C 言語の特徴は , まとまった処理を関数と 強くなり , 離れた行ほど疎な関係になるこ いうプラックボックスの中に閉じこめると ( 3 ) 実は , とあるパソコン通信サービスの とが多くなります。 話。そこは世界て、も珍しい異次元空間て、 , したがって , 密な処理ほど近い所にある いう手法により , 処理を理解しやすくする はっ , と気づいたときはばっさり情報が という点にあります。数十行ならばそれほ ため , ひとつの関数が画面スクロールさせ 消滅しているのて、 , 答える暇もなかった なければ読めない場合て、も , さほど混乱し ど難しいことて、もありませんが , 何千行に のだ。ちなみに , 某所ってどこだという ないはすて、す。 もわたるプログラムを理解するのは , さす と , 「パソコン通信サービス」なんて書く がにたいへんて、す。なぜかというと , あま 処理の内容によって , しなければならな と苛められそうな所だというと , わかる りに行数が多いと , 最後のほうの処理を考 ことは違います。何て、もかんて、もたとえ い List 中で何が起きているのかわからない関数の例 List 相手にまかせすきない関数の例 ひとつの関数さ る す 示 表 に 面 を 果 結 し 変 コ 1 宀、ノ 一 4 し 1 よ : VOid sj is—tO euc(char *fname) FILE *fp; fP ニ open-file(fname) : 3 / * コード変換した結果を画面に表示する * た sjtoeuc(fp); close—file(fp); / * ファイルを閉じる * / 、 V 52 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
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