関数 - みる会図書館


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

1. 月刊 C MAGAZINE 1990年7月号

C 十十 プログラミング 入門 たが , このクラ幻 ntege 「は無限大の数値を 扱うことがてきます ( 注 10 ) 。これは , 実装方 法こそ違いますが , 本連載第 1 , 2 回て、示し たクラス Bignum の完成したバージョンて、あ , % などの基本演算子に加わえ , & などのビットごとの演算子ももって います。また , 入出力のための演算 子くく , > > や数学関数 abs , sqr, gcd など もあります。 ・ RationaI クラス Ration 引は , 有理数を扱うデータ型 てす。この型て、は , ーーのように小数として 割り切れない数値を扱うことがてきます ( 分 母 , 分子が互いに素てあり , 分母はつねに 正の分数て表せる数値 ) 。 + , ー , % などの基 本演算は用意されていますが , ビットごと の演算は使うことがてきません。 ・ CompIex AT & T のクラス comp x と同じ機能を実 装したのが , このクラス Complex-t あり , 複素数を扱います。 このクラスも , 本連載第 2 回て、紹介しまし こて、は詳しい解説は省きますが , たから , 名前は違うものの , AT&T と同じ演算子や 数学関数をもっています。 ・ Fix クラス Fix は , [ ー 1 , 1 ) の範囲の実数を扱 うデータ型て , 実際には 5 つのクラス Fix, Fix16, F ⅸ 24 , F ⅸ 32 , F ⅸ 48 があります。 れらのクラスの違いは , 表現に使われる領 域の大きさてあり , 各 16 , 16 , 24 , 32 , 48 ビットが使われ , それぞれ精度が異なりま す ( 注 11 ) 。当然 , 普通の算術演算は用意され ています。もし扱う数値が範囲からあふれ 出した場合 , 適当な処理関数 ( たとえば , Fix16 overflow saturate) が呼び出されます。 ・ Bits クラス Bits には , ビット ( 0 か 1 のデータ ) を 扱う BitSet と BitString があります。 C ( 十十 ) の魅力には , ビット操作が可能なこともあ りますが , クラス Bits はそれに注目したもの てす ( 注 12 ) クラス BitSet は ,ビット集合を扱うデータ 86 CMAGAZINE 19 7 型てあり , 仮想ビット ( 注 13 ) により , 無限集 合をも扱うことがてきます。一方 , クラス BitString は , ビット列を扱うデータ型てあ り , ビット操作はほとんどクラス BitSet のま まて , さらに , 連結などのビット列として の操作を追加しています。また , クラス BitString には , その仲間として , パターン 照合のためのクラス BitPattern があります。 ・ Randam クラス Randam は , 乱数生成のためのクラ スてあり , 乱数を生成し , その分散を決め , 適切な形て、アプリケーションに渡す何種類 かのクラスからてきています。 クラス RNG は , ほかの乱数発生クラス (ACG, MLCG など ) て、 , 実際の乱数を生成 する基本となるクラスてあり , メンバ関数 asFloat, asDouble をもっています。クラス ACG は , D. E. Knuth の「 The Art of Computer Programming 』第 2 巻に述べら れている LCG (Linear Confgruentail Generator) を実装したものてあり , 非常に 品質の高い乱数を生成します。クラス MLCG は , Pierre L'Ecuyer の MLCG (Multi plicative Linear Confgruentail Genera t 。 r ) を実装したものてす。 クラス Randam は , クラス RNG が生成し た乱数の分散を決めるためのクラスてす。 その分散の種類により , Binomial, Er lang, Geomeric, HyperGeomeric, NegativeExpntI, Normal, LogNormal, Poisson, DiscreteUniform, lJniform, Weibull というクラスがあります。たとえ ば , クラス Binomial は , コンストラクタに 与えられる引数 n と u て決定される二項分布 に従って分散した乱数を提供します。 ・ Data データの集まりを分析するために , クラ ス SampIeStatistic と SampleHistogram が あります。クラス SampIeStatistic は ,double 型のデータを収集し , その統計を求めるこ とがてきます。クラス SampleHistogram は , SampleStatistic の派生クラスてあり , ヒストグラムを出力てきます。 ・ String クラス string は , 文字列を扱うデータ型て、 す。参考文献 [ 1 ] てのクラス string の実装 とは , 異なる方法て実装されているため , C ( 十十 ) の ch ar * の代わりに使え , C の標準 関数 fprintf, strcmp などの引数に使うこと がてきます。 また , 正規表現のために , クラス Regex が "CA-Z] CA-Za-z0-9] * 用意されており , などの正規表現が可能になっています ( 注 14 ) ・ Obstack クラス Obstack ( 注 15 ) は , GNU C ( 十十 ) コンパイラに記号表の作成のために含まれ ていた obstack マクロをクラスとして実装し たものてあり , 大きさが不定のデータ群を 取り扱うデータ型てす。 クラス Obstack が扱うデータは , はじめは 未熟て、大きさが変化しますが , 一度決まれ ば , もう大きさも位置も変化しない , 成熟 したものになります。ただし , 未熟なデー タは , その時点て、処理しているもののみて、 , 残りは熟成したデータとなります。データ の具体例としては , コンパイラの記号表て、 の文字列などがあります ( 最近は , 記号 ( 識 別子 ) の長さに制限をつけたコンパイラなど は滅多にありません ) 。この実装て、は , 巨大 な記憶領域を用意し , 各データに分けえ ています。 ■擬似汎用型 , こまてにあげた抽象データ型以外にも , 注 10 無限といっても , もちろん記憶領域などが許すだ けてある。ただ保想記憶領域に余裕がある機械て , それ を使い切ることは滅多にありえず , 問題になるのは , 領 域の大きさを保存している short 変数てある。 sho 「 t が 16 ビットの言 t 算機ては 1 , 048 , 560 ビット長まててあるが , それを long 変数に変更すれば , さらに大きな数値を扱う ことがてきる。 注 1 1 Fix と Fix16 の違いは , それらの積が F ⅸ ( 16 ビット ) か Fix32 ( 32 ビット ) かてある。 注 12 クラス tege 「は , ビット操作もてきるが , 注目し ているものは整数としてのデータてある。 注 13 想ビットは , 0 * 〃あるいは当 * 〃て表現され る。 注 14 この正規表現の処理手続きは , 優れていることて 言面カ皜い GNU Emacs の「 egex 関数から流用てある。 注 1 5 Obstack は stack of objectsØN6-C ある。

2. 月刊 C MAGAZINE 1990年7月号

Fig. 1 DecIarations dec/aration. dec/aration-specifires init-dec/ararion-/istopt, declaration-speciflres. storage-c/ass-specifires declaration -specifiresopt type-specifier dec/aration-specifires op ご type-qua/ifier dec/aration-specifiersopt init-declarator-/ist: init-dec/arator init-dec/arator-/ist, init-declarator init-dec/arator. declarator declarator initializer 宣言が関数内て、行われた場合 , 静的な局 所変数が生成されます。この識別子は関数 内て、のみ参照が可能てすが , そのオプジェ クトは存在し続けます。必要があれば , そ の内容をポインタを介して返したり , 別の 関数からアクセスしたりすることも可能て、 す。 宣言が関数外て、行われた場合 , そのコン パイル単位内て、のみ有効な広域変数となり ます。 ÄaUtO 記憶クラス指定子 auto は , 関数内て、の宣 言 ( 局所変数の宣言 ) においてのみ使用する ことがてきます。 auto が指定されたオプジ ェクトの実体は , その関数が呼び出された 時点て領域が ( 通常 , スタック上に ) 割り当 てられ , その関数が実行されている間のみ 存在しています。 Fig. 2 Storage-class Specifires srorage-c/ass-specifier. exte rn sati C autO register typedef ■「 egister クラス指定子として扱われますが , 実際に typedef は , 文法規則上においては , 記憶 ntypedef きません。 クトの内容を取得または変更することはて つまり , ポインタを介して ,. そのオプジェ トのアドレスを参照することはてきません。 この記憶クラスが指定されたオプジェク するかもしれません。 オプジェクトをレジスタに割り当てようと よっては , 最適化処理のためにより有効な り当てられるとはかぎりません。処理系に べてのオプジェクトが , 必ずレジスタに割 すのて , この指定子によって指定されたす し , CPU のレジスタ数にはかぎりがありま (CPU) のレジスタに割り当てます。ただ 指定されたオプジェクトをハードウェア は記憶クラスを操作するものてはありませ ん。この指定子は , 基本データタイプに新 しい名前を定義するために使用されます。 以上の記憶クラス指定子が宣言内におい て使用されなかった場合 , その状況により , 次のようなクラス指定が行われます。 1) 関数内で宣言された場合 関数内における局所変数と見なされ , auto が指定されたものとして扱われ ます。 2 ) 関数外で宣言された場合 グローバルなスコープに属するもの としてオプジェクトが定義され , そ の識別子は , ほかのコンパイル単位 における extern 宣言によって参照する ためにリンカに渡されます。 Type specifiers ( 型指定子 ) 宣言において使用される型指定子の定義 は Fig. 3 のとおりてす。 これらの型指定子を使用して , Fig. 4 のデ ータタイプのいずれかが指定されます。 プロジェクト PragmaC 33 って制限を与えることがてきます (Fig. 7 ) 。 すべての型指定子に対して , 型限定子によ ( 型限定子 ) Type qualifiers 定数 ( 列挙定数 ) として宣言されます。 列挙子リストにおける識別子は , int 型の よって定義されます。 列挙型指定子は , Fig. 6 のシンタックスに ( 列挙型指定子 ) Enumeration specifiers ックスによって定義されます。 構造体 / 共用体指定子は , Fig. 5 のシンタ ( 構造体 / 共用体指定子 ) Structure and union specifiers

3. 月刊 C MAGAZINE 1990年7月号

特集最新入門 域確保関数と異なり , 解放する必要が ないのて , 一時的なメモリの使用の際 には便利な関数てある。一般的には ヾ訓 oca 〃を行う関数を呼ぶことになる のだが , GCC ては次のように定義した や訓 oca 〃という関数呼び出しの生成コ ードは , 関数呼び出しをしないてイン ライン展開した機械語になる。 #ifdef __GNUC #define alloca ー builtin alloca #endif コン督ラの内部バス GCC 内部ては複数パスを経てアセンプラ コードを生成する。ソースファイルの中て ターゲットマシンに依存する部分をコンパ クトにまとめ , 次のようなヘッダファイル とターゲットマシンの記述だけにしている。 ①ターゲットマシンの記述 (Machine Description, 以下 MD) ターゲット CPU に依存する部分をまと めたファイルに , 命令の定義や専用の ぞき穴適化のテンプレートなどを記述 する。各パスて必要な C 言語のプログラ ムをこの MD から生成する方式を採って ②ターゲットマシンや OS に関するヘッダフ アイル ターゲットマシンのアーキテクチャ ( ワ ードのビットサイズなど ) や OS に依存す る部分をまとめたもの。 GCC の基本的なアイデアを次に示す。 ・各パスの中間データをメモリ上に展開す る ・構文解析パスでソースプログラムを読み 込み構文木を作る RTL(Register Transfer Language) 生 成部で構文木を RTL という中間コードに 変換する ・さまざまな最適化を RTL に対して施す ・コンパイルしていくパスの前半はレジス タの数が無限だと想定して ( これを仮想レ ジスタという ) RTL の生成 , 操作 , 変換を ・前途の残り後半のパスで , 仮想レジスタ から実際のハードウェアレジスタへ割り 当てる それぞれの関数ごとに以下のパスを実行 する。このパスの中てターゲットマシンに 依存する部分は , 前述の MD ファイルから自 動生成されるものもある。 ・構文解析部 関数全体を読み込んて部分的に構文木 を作成する。データタイプの解析も行 い , 定数の伝搬や結合則に関する簡素 化を用いて最適化を行う。 ・ RTL 生成部 構文木から , 文単位て RTL に変換して いく。ここて if 文や論理式 , 条件式 , 末 覗再帰呼び出しの最適化を行う。 MD て 生成した関数も使う。インライン関数 の処理 ( インライン展開てきるかどうか の判断など ) を行う。ちなみに , 末尾再 帰呼び出しのインライン展開も可能て ある。 ・ジャンプ最適化 RTL の中からジャンプに関する最適化 を行う。これは , ある部分にジャンプ してさらにジャンプする命令を簡単に するものなどてある。このジャンプの 最適化は , RTL の中だけてなく , ほか にも 1 ~ 2 か所て行われる。 ・レジスタスキャン レジスタの使用に関するトレースを行 い , 次のパスのためのデータを集める。 ・共通部分式の削除 (Common Subexpres sion Elimination, 以下 CSE) 定数式の複製をしながら最適化を行う。 ・ループの最適化 ループ内の定数式をループ外へ移動す ・古いレジスタ割り当ての実行 最適化コンパイルのコマンドオプショ ンー 0 〃なしにコンパイルした場合 に , 古いレジスタ割り当てを行う。古 いレジスタ割り当てとは , これまての 普通の C コンパイラが行ってきた変数の レジスタ割り当てのことてあり , ュー ザが明示的に「 egiste 「宣言を行った変数 をレジスタに割り当てることてある。 このパスて , レジスタ宣言した変数を 仮想レジスタに割り当てる。このため , 小規模なデータフロー解析を行う。そ のあとて感積直いというパスを実行 ・データフロー解析 プログラムをベーシックプロックに分 割しながら , 実行しないループを削除 する。計算結果を使わない場合は , 利 用していないその部分を削除する。あ るメモリ参照とその前後の命令を組み 合わせて , マシン特有のアドレッシン グモード ( 自動増加 , 減少など ) を使え るようにする。べーシックプロックと は , 入口と出口以外に制御の出入口が ないプロックのことてある。 データフロー解析結果を用いて 2 ~ 3 個 の命令をひとつにまとめられないかど うかを調べる。まとめられる場合は , 組み合わせ可能なひとつの命令に置き 換える。 ・レジスタクラスの選択 各仮想レジスタは , 実際にどのハード ウェアレジスタクラスに相当するかを 調べる。 ・局所的なレジスタ割り当て べーシックプロック内のレジスタ割り 当てを行う。 ・広域的なレジスタ割り当て 残りの仮想レジスタの割り当てを行う。 ・積み直し ・命令の組み合わせ 特集最新 GNIJ 入門 49

4. 月刊 C MAGAZINE 1990年7月号

匚ー”コ 五ロ 一三ロ はじめて学ぶプログラミンク もないプログラムがてき上がってしまいま て、す。今のところは , 内容に立ち入らず , 構造体なのてす。この例ては , 名前 , 住所 , す。したがって , きちんとしたプログラム 概念だけ理解してください 電話番号をひとかたまりのもの ( 構造体 ) と を書こうとすると , けっこうたいへんて、す。 考え , その新しい一かたまりのもの ( 構造体 型 ) の配列を考えればよいのて、す ( Fig. 2 参 また , この例てはひとかたまりとして扱 うデータの個数が 3 個なのてまだよいほうて 照 ) 。そして , 関数には構造体の配列を渡し ていくのて、す。 こて、いきなり , 構造体の すが , ひとかたまりとして扱うデータの個 配列といわれても , 面食らってしまったの 数が増えてくると , 引数が多くなり , プロ ては , 実際に住所録の構造体を宣言して て、はないて、しようか。これは , 構造体につ グラムが煩雑になってしまいます。 みましよう。 List1 を見てください。これ いて説明するための例て、あり , 心配は不要 このようなことを解決してくれるのが , て , 構造体 struct address data 型が宣言さ れました。 st 「 uct とは予約語てあり , このよ 住所録の構造体 うに構造体を宣言するときに用いられます。 Fig. 3 構造体のしくみ この構造体につけられている名前が poi nt struct address data< あり , 正確には「構造体タグ」 ↑ ( タグ名 ) と呼ばれます。また , 構造体の中 予約語 構造体タグ int X,• の各要素 ( 変数 ) name , address,tel は「メン バ」と呼ばれます。 int y; 住所録の例ては , 構造体の中にさらに配 列 ( 文字列 ) があり , 多少難しいのて , もっ と簡単な例として , ディスプレイ上の点を 考えてみましよう。ディスプレイ上の任意 の点は , 必す x 座標と y 座標からなります。 これは , まさに構造体て扱ったほうがよさ そうて、すね。 ては , ディスプレイ上の点の例て , 構造 体を宣言してみましよう。 List2 を見てくだ さい。これて , 構造体 struct point 型が宣言 されました。この構造体の構造体タグは point てす。そして , メンバは int 型の x と y てす ( Fig. 3 参照 ) 。 次に , 構造体の変数を定義してみましょ う ( 以下 , 断わらないかぎり , 変数は外部変 数を例にします ) 。構造体の最後のとじプレ ースリ〃の後には , 変数のリストを書くこ とがてきます。 List3 を見てください することによって , struct point 型の変数 a, b, c が定義されます。考え方としては a, b, c という名前がついた箱があり , その 箱には , int 型の値を入れることがてきるふ たつの引き出しがついていると仮定します。 その引き出しには , さらに , x と y という名 前がついているのてす ( Fig. 4 参照 ) 。 また , この書式は , 構文的には , int a, b, c : ととてもよく似ていますね。 はじめて学ぶ C プログラミング 119 List 1 Cd 0 「 ー 0 ワ 0 - -0 1 よ 0 乙 00 -4 ・ - -0 ティスプレイ上の点の構造体 List 2 + し十し メンバ コラム宣言と定義 宣言と定義はどう違うのでしようか ? 文章中に , 構造体を「宣言」するとか , なんとか型 の構造体の変数を「定義」すると頻繁に出てきています。しかし , 多くの読者の方は , その違 いを気にしないで , なに気なく読みすごしているのではないかと思います。いったい , 「宣 と「定義」の違いとはなんでしようか ? 簡単にいうと , 「宣言」は指定した属性と名前とを関連づけるだけのものです。それにたい して「定義」は属性をつけるとともに , メモリに領域を割り当てるのです。したがって , 「定義」 は暗黙のうちに「宣言」を含みます。 内部変数では , 宣言と定義が同時に行われます。一般的に内部変数は , 「宣言」するといい ます。本連載でも , 変数宣言として何回も取り上げましたね。たとえば , 「関数の中」で , int X : とすることにより , この関数が呼び出されたときに , int 型という「性質」をもった内部変数 x が , 「メモリ」に領域が割り当てられるのです。この変数 x は , 内部変数なので , 関数呼び出し が終了すると , 当然 , メモリから消減します。 ところが , 外部変数には , 宣言と定義の区別があります。このことについては , すでに説 こで , 簡単に復習してみましよう。 明しました。 外部変数の定義は , 任意の関数の外側で , 一度だけ行われます。たとえば , 任意の「関数の 外」で , int X : とすることにより , 内部変数の場合の変数宣言と同様に , int 型という「性質」をもった変数 x が , 「メモリ」に割り当てられるのです。これを , int 型の外部変数 x の「定義」といいます。 これに対して , この外部変数を参照する関数では , その「関数の中」で , extern int X : のようにします。このとき , 変数 x には , 実際には , メモリ割り当ては行われません。変数 x には , int 型だという性質のみが指定されるのです。これを int 型の外部変数 x を参照するための 「官言」といいます。 同様にして , 構造体について考えてみましよう。構造体を考えるときには , 「宣言」と「定義」 を区別します。 List2 のように構造体を「宣言」すると , 構造体のテンプレート ( 構造体の形 ) だけが宣言さ れ , メモリには何も割り当てられません。しかし , 構造体タグをつけているので , 以下のよ うにすると , struct point 型の変数 a を「定義」できます。 struct point a : このとき , 変数 a は , st 「 uct point 型の性質をもち , 実際にメモリに割り当てられます。ま た , List3 のようにしても , struct point 型の変数 a. b, c が定義できます。この変数の定義

5. 月刊 C MAGAZINE 1990年7月号

かを見るために使用する。有効てない場合 は 0 , 有効な場合は非 0 に設定される。 ・ millitm このフィールドは , されている。 返される値は , double の秒値て、返される。 実際には , サンプルプログラムを見てほし い (diff. c) 。 clock( ) 関数 c ck ( ) 関数は , プログラムの開始から ftime( ) 関数 の経過を示すプロセッサ時間を返すのて、 , ふたつのイベント間を測定するのに非常に 便利てある。この関数の実行により返され この関数は , 現在時刻を ftime ( ) 関数の引 ・ time このフィールドは , GMT からの経過時間を 数が指し示す timeb 構造体に設定する。この る値は , 秒単位のプロセッサ時間と CLK 秒値て、格納される。 構造体は , timeb. h (YsysYtimeb. h) に登録 TCK マクロ ( time. h て定義 ) の積が返され されており , 内容を見てみると 4 つのフィー る。したがって , 実際に必要なプロセッサ ルドから構成されている ( Fig. 2 ) 。 ・ timezone 時間を求めるには , CLK TCK マクロて、割 このフィールドは , GMT と地方時間との差 以下に , この構造体の各フィールドを説 らねばならない。もし , 無効な値の場合は , を分単位て格納する。この値は GMT から西 明する。 1 の値が返される。 に向かって計測され , その反対はマイナス サンプルプログラムを見てほしい (clk. 符号をつけて表現する。なお , この値は , c ) 。このプログラムて、は , sta 「 t と end という ・ dstfag このフィールドには , 夏時間が有効力 フ グローバル変数 timezone から取り出されて 変数の間に 2000 回のループを行っているに すぎないが , 実際にはこの間にいろいろな 処理をさせるとよいだろう。最後には , Fig. 2 timeb 構造体の内容 START と END の差を CLK TCK マクロて、 Turbo C Ve 「 . 2.0 割ってからカウントした回数を表示して終 了している。 st 「 uct timeb ミリ秒単位の値が格納 MS-C Ver. 5.1 struct timeb long time; ShO 「 t millitm, short timezone; short dstflag , time-t unsigned short millitm; short timezone; dstflag , short time, ctime( ) 関数 この関数は , time ( ) 関数によって返され た time t 型の値を引数に取り込んて , 決まっ た書式の文字列て日時の表示を行う機能が ある。決まった書式というのは , 以下のと おりてある。 Tue May 01 12 : 12 : 12 1990 \ n \ 0 表示時間は 24 時間表記になっており , の文字列の最後には改行コードと文字列の 終端を示す NULL 文字がついている。全部 て 26 文字となる。 difftime( ) 関数 この関数は , time t 型の時間について , そ の差を算出する関数てある。計算の結果 , Fig. 3 tm 構造体の内容 MS-C V5. I&TurboC V2.0 も time. h から引用 * / struct tm / * seconds afte 「 the minute— LO, 59 ] int tm-sec; / * minutes after the hou 「一〔 0 , 59 ] int tm_min ; / * hours since midnight— [ 0 , 23 ] int tm-hour; / * dayofthemonth— CI , 31 ] int tm-mday, / * months since January— [ 0 , 1 1 ] int tm_mon; / * years since 1900 int tm-year, / * days since Sunday— LO, 6 ] int tm-wday; / * days since January 1 ー [ 0 , 365 ] int tm-yday, int tm-isdst , / * daylight savings time flag 80 CMAGAZINE 19 7

6. 月刊 C MAGAZINE 1990年7月号

普通は , (fset ' 1S1 (symbo ト function 'ca 「 )) のように使い , 関数の別名定義に使います。 ちなみに , symbol-function は , シンポルか ら関数スロットの値を求める関数てす。 de a 数名 [ 値 [ ュメン村 1 変数を宣言します。変数名シンポルの引 数は評価されません。評価時に変数名シン ポルに値が設定されていなければ , 指定し た値を setq のように代入します。値の既定値 は nil てす。 ドキュメントが指定されていれば , その 文字列はシンポルの属性リスト中に入れら れ , オンラインヘルプによって参照されま す。 defvar がなくても大域変数は使えますが , 後からプログラムを読むときなどに理解を 助けます。また , defva 「を使っておけば , そ のモジュールをロードしたときに , . emacs な どて設定しておいた値を再設定してしまう ことがなくなります。 make-vector 長さ初期値 べクタを新しく作って返す関数てす。 (make-vector3 nil) とすると , 長さ 3 て要素 がすべて nil のべクタがて、きます。 a 「 ef べクタインテックス位置 べクタや文字列要素を参照する関数てす。 (arefpoi2) とすると , 変数 poi に束縛されて いる配列 ( または文字列 ) の , インデックス 2 の位置にある要素を返します。インデック スは 0 オリジンてすから , この場合は 3 つ目 の要素を返します。たとえば , poi の内容が ヾ [ 0 1 2 3 4 5 ] 〃のときは 2 が返ります。 poi の内容が qabcdefg" のときは ?c, つま べクタに関する関数 60 CMAGAZINE 19 7 り 99 が返ります。 aset べクタインテックス位置値 a 「 ef と逆に , べクタや文字列の要素を更新 する関数てす。 (aset poi 2 nil) とすると , 変数 poi に束縛されている配列の , インデッ クス 2 の位置にある要素が nil になります。イ ンデックスは 0 オリジンて、すから , この場合 は 3 つ目の要素が更新されます。たとえば , poi の内容が贒 0 1 2 3 4 5 ドのときは , poi は 0 1 nil 3 4 5 ] 〃となります。 poi の内容が "abcdefg" のときに (aset poi 2 ? z) とすると , poi は "abzdefg" となりま insert 内容 関数 バッフアに関する す。 後ろにポイントを移動します。 ト位置に文字列または文字を挿入し , その とります。現在のバッフアの現在のポイン 文字列 , または文字を表す数値を引数に po intc ト位置のインデックスは , 1 オリジンて、す。 現在のポイント位置を返します。ポイン goto - cha 「インテックス 式 ... を順次評価します。この関数を出ると 引数は , 評価されないて、渡されます。 save—excursion 式 イントを移動します。 引数て、指定されたインデックス位置へポ 引数て指定された変数を , バッファロー make-loca ト valiable 変数 きの状態に戻します。 きには , ポイントとマーカーを , 入ったと カル変数にします。 関数 制御構造に関する たときにバッファローカルになる変数にし 引数て指定された変数を , 代入がなされ make-valiable-buffer-locaa 数 Emacs Lisp には , do 系の制御構文も , 関数 例外処理に関する 外名には , e 「「 0 「 , quit などがあります。 例外名て示される例外を発生します。例 signalflJ 外各値 いるようてす。 Lisp て、は , throw などを例外処理て実現して うべきだと思っていますが , 逆に , Emacs や chatch, unwind-protect などによって行 私個人としては , Lisp の例外処理は , throw Ada などの言語に採用されているものてす。 に関する機構があります。これは , CLU, Emacs Lisp には , 例外処理 ( 工ラー処理 ) 繰り返し評価します。 て , 条件が真てある ( nil て、ない ) 間 , 式 ... を す。使い方は , C や PascaI の while 文と同じ wh ile は , 引数を評価せずに受け取りま h ⅱ e 条件式 のて , そちらを使ってください は , if 文 , while 文 , and 文 , 0 「文などがある の制御構文もありません。制御構文として tagbody と go の制御構文も , block と return dition - case 変数名本体例外処 外を扱います。引数は , 評価されないて渡 本体を実行中 , signa によって発生した例

7. 月刊 C MAGAZINE 1990年7月号

リ . 4 ラタ乙 イラ たのて , それも合わせて見てほしい。グリ ニッジ標準時 ( 以後 GMT ) が基本単位になっ ており , その値がいろいろと変更されるこ とて必要な時間を得ることがてきる。 TZ 変数と tzset( ) 関数 時間に関する環境変数に TZ というのがあ る。これはタイムゾーンを定義してあるも のて , これを使って地方時間と GMT の差を 算出する。算出された時間は , daylight, timezone, tzname の各グローノヾル変数に格 納される。通常 , TZ 変数は SET コマンドて 登録するか , putenv() 関数を使用して環 境変数に登録しておかなくてはいけない 環境変数に登録された TZ から GMT との違 いを各変数に格納するには , tzset() 関数 を使用する。この tzset( ) 関数は , Turbo C Ver. 2. O,MS-C Ver. 5.1 いずれにもサポー トされており , サンプルプログラムは , tzset() 関数を使用したいちばん簡単な例 てある (tzset. c) 。 TZ 変数に格納される値には , いくっかの 決まった方式がある。 tzset() 関数て使用 している例を取り上げてみると「 TZ = EST5 PDT 」となっている。最初の 3 文字てある EST は , 現在の時間帯を指している文字列てあ る。そして真ん中の数字は , 現在の時間帯 と GMT との差を示している。つまり , 5 な ら GMT から東に向かって 5 時間のところを EST とし , 8 なら PST となる。もし , ー 1 なら ョーロッパ大陸ということになる。 最後の 3 文字は , 省略可能な地方時間の夏 時間を指している。ちなみに , PDT とは , Pacific Daylight Savings Time の意味て あり , 太平洋夏時間のことてある。 もし , この TZ 環境変数が登録されていな ければ , デフォルト値として ,MS-C Ver. 5.1 ては「 TZ=PST8PDT 」が採用され , Turbo C Ver. 2.0 ては「 TZ = EST5EDT 」が採用され ることになっている。 Fig. 1 各関数どうし関係 stime( ) ※ MS-DOS の システム日時 time_t GMT ( 1 月 1 日 , 1970 ) からの秒数 ctime( localtime( ) gmtime( ) strut tm GMT 各フィールドに値を入れる asctime( 1 2 : 1 2 : 12 \ n \ 0 Tue May 1 strut tm 地方時間 各フィールドに値を入れる asctime( ) mktime( ド struct timeb ftime( ) -strdate( ド 05 / 01 / 09 \ 0 -strtime( ド 1 2 : 1 2 : 12 \ 0 * MS-C だけ ※ Tu 「 böだけ C プログラマのためのランタイムライプラリ入門 79

8. 月刊 C MAGAZINE 1990年7月号

特新最新入門 ンタラクテイプを指定する文字列 , 関数の ドキュメント文字列などからなる (C の ) 構造 体へのポインタてす。 なお , Sub 「て、ない関数は , バイトコンパ イルされたものも含めて , リスト構造にな っています。 ウインドウ GNU Emacs のウインドウを表すデータ 型てす。 ウインドウ型のデータを表す入力構文は ありません。出力においては , # く window 1 on poi> のように表します。これは , バッファ poi を 内容とするウインドウて、す。 プロセス GNU Emacs によって起動された , UNIX のプロセスを表すデータ型てす。 プロセス型のデータを表す入力構文はあ りません。出力においては , # く process poi> のように表します。これは , 名前が poi てあ るプロセスて、す。 VOid シンポルの値セルなどて、使われ , 現在値 が定義されていないことを表す型てす。 れを変数の値や関数として参照すると , 工 ラーとなります。ューザが直接使わない , 内部的な型てす。 Emacs Lisp は , 前述したとおり , Common Lisp に似せたものになっています。したが って , 関数も Common Lisp に似たものが多 いようてす。ただし , これも , 前述したよ うに , GNU Emacs の記述言語としての機 能にわりきって効率を追求しているため , Common Lisp に比べて , 非常に簡単なもの 関数 になっています。 関する関数 言や定義に defun 関数名ラムダリスト [ ン村 分は省略可能という意味てす。 なお , ここてヾにとツ〃て囲われた部 [ 文献 10 ] や , オンラインヘルプを見てくだ 代表的なものをとりあげます。くわしくは , , こては , そのような特殊な関数のうち , されています。 特殊なため , それ用の関数がいろいろ完備 また , GNU Emacs のデータ型や目的が インタラクテイプ指定 ] 一式・・・ a に 1 , b に 2 , c に nil, d に nil が渡ります。 となっているとき , 実引数がヾ ( 12 ) 〃なら , (a &optional b c &rest d) ダリストが , 指定することがてきます。たとえば , ラム 以下の随意変数や , & 「 est 以下の余剰変数を こには , 通常の変数のほかに , &optional ラムダリストは , 仮引数のリストてす。 という式を入れます。 interacitive 指定式 ... ) (lambda ラムダリストドキュメント れます。関数名のシンポルの関数スロット を行います。引数は , 評価されないて、渡さ defun は , 普通の Lisp と同様 , 関数の定義 ( 1 2 3 4 5 6 ) 数 interactive によって行います。 Emacs のコマンドとするための宣言て , 関 インタラクテイプ指定は , この関数を GNU 重要な関数にはつけておくと便利てす。 字列て , オンラインヘルプが参照します。 ドキュメントは , その関数を説明する文 ります。 なら , a に 1 , b に 2 , c に 3 , d に ( 4 5 6 ) が渡 interactive 内容 その関数がコマンドとして呼ばれたとき の , 引数の渡し方を指定します ointeractive が関数として呼ばれたときは , 引数を評価 せず , nil を返します。 引数は , 通常 , 文字列の形て指定されま す。文字列中の文字が , それぞれ TbI. 3 に示 したような受け渡し形態を表します。 バッフアから値を読み取る形態の場合 , そ の後の文字列がプロンプトになります。 たとえば , (interactive"finput file name : *nr") と指定されている関数をコマンドとして呼 んだ場合 , ミニノヾッフアに input file name . とプロンプトを出してファイル名を入力さ せた後 ( 補完機構が働きます ) , 第 1 引数にそ のファイル名 , 第 2 引数に現在のリージョン の開始点 , 第 3 引数に現在のリージョンの終 了点を渡して関数を呼び出します。 引数は , 文字列てなくてもかまいません。 この場合 , 引数を評価したリストが , 実引 数のリストとなります。たとえば , (interactive(list'poi qwe)) と指定されている関数をコマンドとして呼 んだ場合 , 第 1 引数に poi , 第 2 引数に qwe を 渡して関数を呼び出します。おもに , 既存 のインタラクテイプ指定文字て表せないパ ターンのときに使います。 その関数に引数がないときは , たんに は , (defun lst (x) ()a 「 x)) します。たとえば , シンポルの関数スロットに , 関数を設定 fset シンボル関数 と指定してください (interactive) 特集最新 GNIJ 入門 59 と同じことてす。 (fset 'lst '(lambda (x) ()a 「 x)))

9. 月刊 C MAGAZINE 1990年7月号

ライフボート 0 「 m 面 00 (ompiler 「 5 Lattice C ポインタになっています。環境変 イプラリは , この変数を参照して , Lattice C 数は , Fig. 1 のような形式て入って 80X87 がついていれば , 80X87 用の グローバル変数 ライプラリを呼び出しています。 環境変数の追加および削除は , NDP が 0 のときは , 80X87 なし , 0 以 ① - STACK それぞれ関数 getenv( ) , rmvenv( ) 外のときは , 80X87 ありを示してい スタックの大きさを指定します。 よって行うことがてき , それぞれ , ます。 スタックには , 関数が呼び出さ この変数 en ⅵ「 on を変更しています ⑦ - PSP れたときの戻り番地や , 自動変数 ( ListI の使用例を参照 ) 。 (static や extern のキーワードなし 標準時間に対応する名称 ( 3 文 プログラムセグメントプレフィ ④ e 「「 no に , 関数内て、定義された変数 ) が割 字)てす。関数 tzset( ) て、初期化され ックス (PSP) へのポインタて、す。 り当てられます。したがって , 多 MS ー DOS て、発生したエラーを示 PSP については , MS-DOS のマニ ます。 量の自動変数を定義している場合 すェラー番号を , UNIX のエラー番 ュアルや参考書を参照してくださ ⑩ daylight には , STACK に , 必要なスタック 号に変換して代入されます。プロ の大きさを指定しておかないと , 標準時間に対応する名称 ( 3 文 グラムスタート時には 0 に初期化さ 一般に , PSP を書き換えたりす 実行時にスタックオーパフローが れますが , その後 , 工ラーが発生 字 ) て、す。関数 tzset ( ) て、初期化され ることはしないほうがいいて、しよ しても , ライプラリて、 , 0 に設定し 起きます。 ます。 直されることはありません。 ⑧ timezone @tzdtn ② - DOS 関数 pe 「「 0 「は , e 「「 no に基づい MS-DOS のバージョン番号が入 て , 対応するエラーメッセージを 夏時間に対応する名称 ( 3 文字 ) グリニッジ標準時との時間差を て、す。関数 tzset( ) て、初期化されま っています。プログラマは , この 表示します。 秒て、表したものて、す。関数 tzset() 変数を参照することて , DOS のバ て、初期化されます。 す。 ⑤ - MODEL ージョンを調べることがてきます。 ⑨ tzname ⑩ - XMODE DOS の第 1 バイトには , DOS の メモリモデルに対応した番号が , メジャーバージョン ( ヒ。リオドより 入ります。プログラムて、 , メモリ 実行モードが , リアルモードか , タイムソ・一ン名て、す。関数 tzset ( ) 前の番号 ) が , 第 2 バイトには , マ モデルをチェックすることがて、き プロテクトモードかを表していま て、初期化されます。 イナーバージョン ( ヒ。リオドより後 す。対応は Tbl.2 のとおりてす。 ます。 ⑩ tzstn メモリモデルと番号の対応は , ろの番号 ) が入っています。 TbI. 1 のようになっています。 ③ environ TbI.2 ⑥ -NDP -XMODE 環境変数へのポインタてす。変 0 数 en ⅵ「 on を参照することて , 現在 80X87 数値演算プロセッサが , 実 1 定義されている , 環境変数を調べ 行中のマシンについているかどう 2 ることがてきます。最後は , NULL かを示します。浮動小数点演算ラ Fig. 1 環境変数へのポインタの配列 TbI. 1 メモリモテルと番号の対応 メモリモデル - MODEL 0 1 2 3 モード リアルモード (MS-DOS) リアルモード ( OS / 2 の DOS 互換ボックス ) プロテクトモード ( OS / 2 ) environ の使用例 List 1 .COM/PEC=command.com "PATH=a:*bin;a:*red;a:*1c" ” RED=a:*red ” envlron extern Char **environ; char **p; for(p = environ; *p; p 十十 ) { printf("YnYtXs",*p); / * すべての環境変数を表示する * / NULL(O) lnformation from Compiler Makers 153

10. 月刊 C MAGAZINE 1990年7月号

ーロ が , 関数の外部で行われているときは , 普通の外部変数のときと同様に考えて , struct point 型の変数 a を「定義」するといいます。 この変数の定義が , つまり関数の内部で行われていれば , 普通の内部変数のときと同様に 考えて , struct poi 猷型の変数 a を「宣言」するといいます。 Fig. 4 構造体変数の構造 匚ー司 構造体のメンバへのアクセス それては , まず , 構造体のメンバへのア クセスを説明します。構造体おのおののメ ンバにアクセスするには , 以下のように行 います。 構造体名 . メンヾー こて , ピリオドヾ は , 「構造体メン バ演算子」と呼ばれ , 構造体名とメンバとを 結びつけるものてす。たとえば ,struct point 型の変数 a が以下のように定義されていると します。 struct point a ; このとき , a. x と a. y に , 点 ( 100 , 20 の を代入したければ , 以下のようにします。 100 ; = 200 ; このように構造体名 . メンバとして , 普通 の変数と同じように扱うことがてきます。 構造体の変数 ( 2 ) 構造体変数の初期化 List2 のように struct P0int 型を宣言した後 て、 , この構造体の変数 a , b, c を定義するこ 構造体変数も普通の変数と同じように初 ともて、きます。それには , 以下のようにし 期化することがてきます。次のように , 構 ます。 POINT a, b, c : 造体変数の定義の後に , 各メンバに対応す struct point a, b, c ; と宣言するのと , る定数式の並びをつけ加えればよいのて、す。 たとえば ,struct point 型を外部て、宣言し struct point a, b, { 100 , 200 } ; ていると , その下の各関数ては , いっても , と宣言するのて、は , まったく同値になりま st 「 uct point a こうすることにより , a. x が 100 て、 a. y が 200 このようにして , 変数を宣言てきます。 す。 typedef をするならば , 構造体タグを省 を初期値とする struct point 型の変数 a が定 略してもかまいません ( 構造体タグは , typedef 義て、きます。これは , 多次元配列の初期化 を使わないときても省略は可能てす。たと と同様てすね。 えば ,List3 などのときには , 構造体タグ point は省略て、きます ) 。つまり , List5 のようにし もうひとつ , typedef を用いる方法があり ても , PO T 型の構造体が宣言て、きます。 ます。たとえば , 前の例だと , 必ず struct 構造体タグ変数の並び 構造体は , 入れ子 ( ネスト ) にして用いる となって , 構造体変数の定義が長くなって ことがて、きます。 しまいます。これが嫌なときには , typedef たとえば , 円は , その中心座標と半径て、 いままて、 , いろいろな方法て、構造体を宣 を用いて新しい型を作ってしまうのて、す。 表すことがて、きます。円を表す構造体の構 言することを学びましナ こては , 構造 たとえば , List4 のようにします。このよ - フ 造体タグを ci 「 c 厄とすると ,List6 のようにな にすると , この struct point 型を新たに 体のアクセスについて説明します。 3 点の座標を表す構造体 構造体の入れ子 1 : struct triangle { struct point pl; / * 座標 1 * / 2 : 3 : struct point p2; / * 座標 2 * / struct P0int P3; / * 座標 3 * / 4 : x, y は int 型 ひとかたまりで変数となっている 構造体の変数を定義例 typedef を用いた例 1 : typedef struct point { 2 : int x; 3 : int y; 4 : } POINT,• List 4 List 3 0 よし十》十し 構造体タグを省路した例 List 5 1 ーっ 0 っ 0 -4 ・ POINT 型として用いることがて、きます。 つ List 7 List 6 1 : struct circle { / * 中心座標 * / 2 : struct point center; / * 半径 * / 3 : i nt rad i u S : 120 CMAGAZINE 19 7