第9回 関数とプログラム構造(3)

第9回 関数とプログラム構造(3)
再帰
 プリプロセッサ

 ファイルの取り込み
 マクロの置換
 条件付き取り込み
再帰呼び出し




関数が、自分自身を呼び出すことを再帰呼び出しと
いう
再帰呼び出しは、アルゴリズム(処理の流れ)的に
使用すると記述がすっきりする場合がある。
ただし、関数呼び出しは、呼び出しオーバヘッドが
かかるので、処理が遅くなる
無限再帰をしないように気をつける
 再帰を停止する条件を必ずつける

再帰が使われる例
 階乗の計算
 数字から文字列への変換
 quick sort (qsort)
再帰を使った例) 階乗計算
int kaijou(int n){
if( n > 1 )
再帰呼び出し
return (n*kaijou(n-1));
else if( n = 1 )
return 1;
else{
printf(" illegal number : %d \n",n);
return -1;
}
}
Cのプリプロセッサ



Cでは、プリプロセッサによって言語仕様が与えられ
る
コンパイレーションの分離した最初のステップ
実際の動作
 ファイルの取り込み
... #include
 トークンの文字列への置換 ... #define

プリプロセッサによって、マシン依存やシステム依存
のコードを分離したり、選択可能にする
ファイルの取り込み

ファイルを取り込む指令
<ヘッダファイル名> ... システム標準のヘッ
ダファイル。システムのinclude directoryでヘッダファイル
を探す
 #include "ヘッダファイル名" ... ユーザのヘッダファイル。
ユーザの指定したディレクトリかcwdから探す
 #include



取り込み指示されたファイルは、その場所にその内
容が展開される
ヘッダファイルにファイル間で共有する関数のプロト
タイプ宣言や、extern宣言、#define などを置くこと
でバグが混入することを抑える
取り込むヘッダファイルを修正したら、取り込むソー
スファイルは全て、コンパイルし直さなければ修正
は反映されない。
マクロの置換 - #define



#define name 置換テキスト ... name を置換テキストに置き換えて
定義する ⇔ #undef name ... nameを未定義にする
#define 定義された名前の通用範囲は、定義された場所からソー
ス・ファイルの最後まで
定義に、以前の定義を用いてもよい
#define LENGTH 10
#define SQUARE LENGTH*LENGTH



置換は、文字記号に対してのみ行われ、””で囲まれる文字列定数
には適用されない
名前、置換テキストは任意のものでよい
マクロの置換は、関数呼び出しの代わりに使用できる


#define max(A,B) ((A) > (B) ? (A) : (B))
マクロの置換を乱用すると、バグの温床になるので使用には注意を
する。
マクロの置換による副作用の考察
#define による置換は、単なる文字列の置き
換えなので、使い方によっては正しくない処
理となる
 #define square(x) (x)*(x)
square(z+1); はどのように展開されるか?
 #define maxof(a,b) ((a) > (b) ? (a) : (b))
maxof(i++,j++)は、何がまずいのか?

#による””内への置換
””(引用符)で囲まれた中の仮引数は置換さ
れない
 置換テキストの中でパラメータ名の前に#を
置くと””で囲まれた文字列に展開される
 #define dprintf(expr) printf(#expr " = ...." );
⇒ printf(" expr = ");

プリプロセッサ用の連結演算子##
プリプロセッサ用の##演算子は、マクロ展開
の最中に2つの引数を連結する
 #define paste(front,back) front ## back

 paste(name,1)
れる
⇒ name1 という文字記号が作ら
条件付き取り込み

#if 定数整数式



定数整数式が真ならば、#elif か#else あるいは#endifまで取り込み
偽ならば、スキップ
#ifdef 名前 ... 名前が前に定義されていれば以下をとりこ
み
⇔ #ifndef 名前 ... 名前が定義されてなければ



#elif ... プリプロセッサのelse if にあたる
#else ... プリプロセッサのelse にあたる
#endif ... 条件付き取り込みを閉じるために#ifや#ifdef に対
応して必ず1対1で必要