第四章ノートThe C Programming Lanuageを抜粋する


第四章関数とプログラム構造
関数は、大きな計算タスクをいくつかの小さなタスクに分解することができます.適切に設計された関数は、プログラム内で理解する必要のない具体的な操作の詳細を隠すことができ、プログラム全体の構造をより明確にし、プログラムの修正の難しさを低減することができます.
4.1関数の基礎知識
関数の定義形式は次のとおりです.
        (     )
{
     
}

関数定義の各構成部分は省略できます.最も簡単な関数は次のとおりです.
dummy() {}

関数定義で戻り値タイプが省略されている場合、デフォルトはintタイプです.
関数がソースファイルに表示される順序は任意です.各関数が複数のファイルに分離されないことを保証すれば、ソースプログラムは複数のファイルに分割できます.
呼び出された関数はreturn文を通じて呼び出し者に値を返し、return文の後ろには任意の式:return式;必要に応じて、式は関数の戻り値タイプに変換されます.式の両側には通常、カッコのペアが付けられます.ここでカッコはオプションです.
4.3外部変数
外部変数は関数の外に定義されるため、多くの関数で使用できます.C言語では1つの関数で他の関数を定義することは許されないため、関数自体は「外部」である.デフォルトでは、外部変数と関数には、同じ名前で外部変数のすべての参照(この参照が個別にコンパイルされた異なる関数から来ても)が実際に同じオブジェクトを参照する性質があります(標準では、この性質を外部リンクと呼びます).
外部変数はグローバル範囲でアクセスできるため、関数間のデータ交換に関数パラメータと戻り値の代わりに使用できる方法が提供されます.任意の関数は、名前から外部変数にアクセスできます.もちろん、この名前は何らかの方法で宣言する必要があります.
4.4役割ドメイン規則
名前の役割ドメインとは、プログラムでその名前を使用できる部分を指します.関数の先頭に宣言される自動変数の場合、その役割ドメインは変数名を宣言する関数です.異なる関数で宣言された同じ名前のローカル変数間には何の関係もありません.関数のパラメータも同様であり,実際には局所変数と見なすことができる.
外部変数または関数の役割ドメインは、宣言された場所から始まり、その存在する(コンパイルされる)ファイルの最後に終わります.
宣言後に使用:外部変数または関数の場合、main関数の前に宣言する必要があります.main関数を呼び出すことはできません.そうしないと、すべて呼び出すことはできません.
外部変数の定義の前に変数を使用する場合、または外部変数の定義と変数の使用が同じソースファイルにない場合は、対応する変数宣言でキーワードexternを強制的に使用する必要があります.
外部変数の宣言と定義を厳密に区別することが重要です.変数宣言は、変数のプロパティ(主に変数のタイプ)を説明するために使用され、変数定義はそれ以外にメモリの割り当てを引き起こします.次の文をすべての関数の外部に配置します.
int sp;
double val[MAXVAL];

この2つの文は、外部変数spとvalを定義し、記憶ユニットを割り当てます.この2つの文は、ソースファイルの残りの部分の宣言としても使用できます.次の2行の文は次のとおりです.
extern int sp;
extern double val[];

ソースファイルの残りの部分にintタイプの外部変数spとdouble配列タイプの外部変数val(配列の長さは他の場所で決定される)が宣言されていますが、この2つの宣言には変数が確立されていないか、ストレージユニットが割り当てられていません.
4.5ヘッダファイル
各モジュールの関数と変数は、個別のファイルに配置され、これらのファイル間の共有の定義と宣言の問題も考慮する必要があります.私たちはできるだけ共有の部分を集中して、このように1つのコピーだけを必要として、プログラムを改善する時もプログラムの正確性を保証しやすいです.これらの共通部分をヘッダファイルに配置し、ヘッダファイルを使用する必要がある場合にincludeコマンドで含めます.
このヘッダファイルでは、すべての関数を宣言し、各個別のファイルにヘッダファイルを含め、対応する関数を具体的に定義します.
一部の中規模のプログラムでは、プログラムの各部分が共有するオブジェクトを1つのヘッダファイルだけで保存することが望ましい.大きなプログラムでは、より多くのヘッダファイルを使用する必要があります.私たちはそれらを丹念に組織する必要があります.
4.6静的変数
外部変数と関数をstatic宣言で限定し、その後宣言されるオブジェクトの役割ドメインをコンパイルされたソースファイルの残りの部分に限定することができます.外部変数を内部変数に変更することに相当します.staticで外部オブジェクトを限定することで、外部オブジェクトを隠す目的を達成できます.これにより、変数と関数の名前が同じプログラムの他のファイルの同じ名前と衝突しません.
staticは、内部変数を宣言するためにも使用できます.staticタイプの内部変数は自動変数と同様に、ある特定の関数のローカル変数であり、その関数でのみ使用できますが、自動変数とは異なり、その関数が呼び出されるかどうかにかかわらず、自動変数のように、その関数が呼び出され、終了するにつれて存在し、消えてしまいます.すなわち、staticタイプの内部変数は、ある特定の関数でしか使用できないが、常に記憶空間を占有する変数である.
4.7レジスタ変数
register宣言は、宣言された変数がプログラムで使用される頻度が高いことをコンパイラに伝えます.register変数をマシンのレジスタに置くことで,プログラムをより小さくし,実行速度をより速くすることができると考えられる.ただし、コンパイラはこのオプションを無視できます.
register宣言は、自動変数および関数の形式パラメータにのみ適用されます.
4.8ブロック構造
C言語では、関数に関数を定義することはできません.ただし、関数ではブロック構造として変数を定義できます.変数の宣言(初期化を含む)は、関数の開始カッコの後に続くだけでなく、複合文の開始を識別する他の左カッコの後に続くこともできます.このように宣言された変数は、ブロック外の同じ名前の変数を非表示にすることができ、それらの間には何の関係もなく、左カッコに一致する右カッコが現れるまで存在します.
良いプログラム設計スタイルでは、変数名が外部の役割ドメインの同じ名前を隠すことを避けるべきです.そうしないと、混乱やエラーを引き起こす可能性があります.
4.9初期化
明示的な初期化を行わない場合、外部変数と静的変数はいずれも0に初期化され、自動変数とレジスタ変数の初期値は定義されません(すなわち、初期値は不要な情報です).変数を定義する場合は、変数名の直後に等号と式を付けて変数を初期化できます.
外部変数と静的変数の場合、初期化式は定数式でなければなりません.一度だけ初期化します(概念的にはプログラムが実行される前に初期化します).自動変数とレジスタ変数の場合、関数またはブロックに入るたびに初期化されます.
自動変数とレジスタ変数の場合、初期化式は定数式でなくてもよい.式には、関数呼び出しを含む、この式の前に定義された値を任意に含めることができる.
4.10再帰
C言語の関数は再帰的に呼び出すことができ、すなわち、関数は直接または間接的に自身を呼び出すことができる.
再帰呼び出し中に処理値を格納するスタックをどこかで維持する必要があるため、再帰呼び出しはメモリのオーバーヘッドを節約しません.再帰の実行速度は速くないが、再帰コードは比較的コンパクトであり、対応する非再帰コードよりも記述と理解が容易である.ツリーなどの再帰的に定義されたデータ構造を記述する際に再帰を使用するのは特に便利である.
4.11 Cプリプロセッサ
概念的には、プリプロセッサはコンパイル中に単独で実行される最初のステップである.2つの最も一般的なプリプロセッサ命令は、コンパイル中に指定されたファイルの内容を現在のファイルに含めるためのinclude命令と、タグの代わりに任意の文字シーケンスを使用するdefine命令です.
11.1ファイルに含まれるファイルに含まれる命令(すなわち、include命令)は、大量のdefine命令の処理および宣言をより容易にする.ソースファイルでは、次のような形をします.
#include "   " #include 

の行は、ファイル名で指定したファイルの内容に置き換えられます.ファイル名が引用符で囲まれている場合は、ソースファイルの場所でファイルを検索します.この場所にファイルが見つからない場合、またはファイル名がカッコで囲まれている場合は、対応するルールに従ってファイルが検索されます.このルールは、特定の実装に関連しています.含まれるファイル自体には、#includeコマンドも含まれる.
11.2マクロ置換マクロ定義の形式は以下の通りである.
#define       

その後、名前記号が表示される場所はすべて置換テキストに置き換えられます.
define命令で定義された名前の役割ドメインは、その定義点からコンパイルされたソースファイルの末尾まで終了します.マクロ定義では、前述のマクロ定義も使用できます.置換は記号のみで行い、引用符で囲まれた文字列には機能しません.
11.3条件は、前処理の実行中に計算される条件文を使用して、前処理自体を制御することができることを含む.
if文は、sizeof、タイプ変換演算子、またはenum定数を含むことができない定数整数式を評価し、式の値が0に等しくない場合は、endif、elif、またはelse文に遭遇するまで、その後の各行を含む(プリプロセッサ文elifはelse ifに類似する).#if文では、名前が定義されている場合に1の値を持つ式defined(名前)を使用できます.それ以外の場合、値は0です.
C言語は、名前が定義されているかどうかをテストするために使用される2つの前処理文ifdefとifndefを特別に定義します.