C言語学習入門(六)前処理指令:マクロ、条件コンパイル、ファイル含む

3422 ワード

プリプロセッシングめいれい
1.C言語はソースプログラムをコンパイルする前に、いくつかの特殊な前処理命令(例えば、以前使用した#includeファイルに命令が含まれている)を説明します.
新しいソースプログラム(このプロセスをコンパイル前処理と呼ぶ)を生成し、その後通常のコンパイルを行う.
2.前処理命令と一般的なC文を区別するために、すべての前処理命令は記号「#」で始まり、最後にセミコロンを使わない
3.前処理命令は、プログラムの任意の場所に表示され、その作用範囲は、その出現位置からファイルの最後までである.
ソース・プログラムの先頭にできるだけ前処理命令を書くことに慣れています.この場合、その役割範囲はソース・プログラム・ファイル全体です.
パラメータなしのマクロ定義
#defineマクロ名文字列
例えば#define ABC 10
右の文字列も省略できます.例えば、define ABC
プリプロセッシングをコンパイルするときに、ソース・プログラム内のすべてのマクロ名を右側の文字列に置き換え、定数を定義するのによく使用されます.
マクロ名の有効範囲は、定義された場所からファイルの終了までです.マクロ定義の役割ドメインを終了する必要がある場合は、#undef ABCコマンドを使用します.
マクロ名は一般に大文字で変数名と区別されますが、小文字でも構文エラーはありません.
マクロを定義するときに定義したマクロ名を参照できます
#define R 3.0
#define PI 3.14
#define L 2*PI*R
パラメータ付きマクロ定義
#defineマクロ名(パラメータリスト)文字列
前処理のコンパイル時に、ソース・プログラムのすべてのマクロ名を文字列に置き換え、文字列のパラメータをマクロ名の右側のパラメータ・リストのパラメータに置き換えます.
#include
#define average(a, b) (a+b)/2
int main ()
{
    int a = average(10, 4);//(10+4)/2に置き換える
printf(「平均値:%d」,a);
    return 0;
}
マクロ名とパラメータリストの間にスペースを付けることはできません.そうしないと、スペースの後ろのすべての文字列が置換された文字列になります.
#define R (a) (a+5)    
void test()
{
    int a = R(5);//この場合の置換の結果は、int a=(a)(a+5)(5);
    printf("%d", a);
}
パラメータ付きマクロは、展開時に単純な文字とパラメータの置換のみを行い、計算は行われません.
したがって、マクロを定義する際には、文字列のパラメータまたは結果をカッコで囲むのが一般的です.
置き換えの原則はプリコンパイル時に覚えておく
関数との違い
使用プロセス全体から,パラメータ付きマクロ定義は,ソースプログラムに現れる形式が関数に似ていることが分かった.しかし、両者には本質的な違いがあります.
1>マクロ定義は、ストレージスペースの割り当て、パラメータタイプの一致、パラメータの転送、戻り値の問題には関与しません.
2>関数呼び出しはプログラム実行時に実行され、マクロ置換はコンパイル前処理フェーズのみで行われます.したがって、パラメータ付きマクロは関数よりも実行効率が高い.
前処理命令:条件コンパイル
プログラムの一部のコードは一定の条件を満たす場合にのみコンパイルされ、
コンパイルに参加しない場合(コンパイルに参加するコードのみが最終的に実行されます)、これが条件コンパイルです.
一般的な使い方:
#if条件1
 ...code1...
#elif条件2
 ...code2...
#else
 ...code3...
#endif//条件コンパイル終了フラグ
#ifと#elifの後の条件は一般にマクロ定義を判断する変数ではなく、条件コンパイルはコンパイル前に行う判断であるため、
マクロ定義もコンパイル前に定義され、変数は実行時に発生し、使用する意味があります.
#define MAX 11
int main ()
{
#if MAX == 0
printf(「MAXは0」);
#elif MAX > 0
printf(「MAXが0より大きい」);
#else
printf(「MAXが0未満」);
#endif
    return 0;
}
マクロを定義したかどうか:
#ifdefined(MAX)/#ifdefの使用と#ifdefined()の使用はほぼ一致する
     ...code...
#elif!defined(MAX)/#ifndefまた#if!defined()の使い方はほぼ一致しています
#endif
#ifndef whichHead //     
//#ifdef   //     
#define whichHead
#endif   //   (             :               ,             ,       
//              #ifndef whichHead  #define whichHead           :#endif)
#if defined (AAA) && !defined (BBB) && 3*5>0 //#if          :        ,      
#endif

前処理命令:ファイルに含まれる
1.第1の形式#include<ファイル名>
C言語ライブラリのファンクションヘッダファイルがあるディレクトリに直接ファイルを探します
2.第2の形式#include“ファイル名”
システムはまずソースプログラムの現在のディレクトリの下で探して、もし見つからないならば、更にオペレーティングシステムのpath経路の中で探して、最後にやっとC言語ライブラリの関数のヘッダファイルの所在するディレクトリの中で探します
注意:#include命令は、a.hがb.hを含み、b.hがc.hを含むようにネストされることを許可するが、a.hがb.hを含み、b.hがa.hを含むように再帰的に含むことは許されない.
#includeコマンドを使用すると、同じヘッダファイルが複数回含まれるため、コンパイル効率が低下する可能性があります.
解決方法:含むファイルに条件コンパイル命令を加え、関数の重複定義を防止する
次のようになります.
       #ifndef c_program_cc_h//マクロが定義されていない場合は、1つを定義し、関数1,2をプリコンパイルします.定義されている場合はコンパイルを実行せずに#endifにジャンプ
#define c_program_cc_h
method 1();
method 2();
………….
#endif