前処理の詳細およびマクロ(C)

4451 ワード

1.事前定義記号
  • __FILE__:コンパイルするソースファイル
  • __LINE__:ファイルの現在の行
  • __DATE__:ファイルがコンパイルされた日付
  • __TIME__:ファイルがコンパイルされた時間
  • __stdC__:コンパイラがANSICに従う場合、その値は1です.そうでない場合、
  • は定義されません.
    これらの事前定義記号はc言語に組み込まれています
    eg:printf(“file:%s line:%d”, __FILE__, __LINE__);
    2. #define
  • #define定義識別子
  • 構文:#define name stuff
  • 注意:定義されたstuffが長すぎる場合は、最後の行を除いて、各行の終わりの後に航続符
  • を付ける数行に分けて書くことができます.
    例:
    1. #define DEBUG_PRINT printf("file:%d\t line:%d\t \
                                date:%s\t time:%s
    ", \ __FILE__,__LINE__, __DATE__<__time__ case="" break="" do_forever="" for="" reg="" register=""/>
  • 上記の例では、#defineで定義された識別子の最後の末尾にセミコロンがないことに注意することができる.これは、置換時に構文エラー
  • が発生することを防止するためである.
  • #define定義マクロ
  • defineメカニズムは、パラメータをテキストに置き換えることを可能にする規定を含み、このような実装は、通常、マクロまたは定義マクロ
  • と呼ぶ.
  • 申明方式:#define name(parament-list//はカンマで区切られたシンボルテーブルであり、stuffに現れる可能性がある)stuff
  • 注意:パラメータリストの左かっこはnameに隣接する必要があります.パラメータリストと左右の括弧の間に空白がある場合、パラメータリストはstuffの一部として解析され、例を挙げて説明します.
    #define SQUARE( x ) x * x
    
    int a = 5;
    printf("%d
    ", SQUARE( a + 1 ) ); // 36, 11 printf("%d
    ", a + 1 * a + 1); // 11 // : #define SQUARE(x) (x) * (x) // printf("%d
    ", (a+1) * (a+1));
  • 上記の問題を回避するためにカッコを使用したが、シンボル優先度の問題が発生する可能性があるか、
  • を例に挙げて説明する.
  • #define DOUBLE(x)   (x) + (x)
    
    int a = 5;
    printf("%d
    ", 10 * DOUBLE(a)); // printf("%d
    ", 10 * (5) + (5) ); // 100, 55, , #define DOUBLE(x) ( (x) + (x) ) // printf("%d
    ", 10 * ((5) + (5)) );
    したがって、数値式を評価するためのマクロ定義には、マクロ定義を使用するパラメータにおけるオペレータまたは隣接オペレータ間の予想できない相互作用
  • を回避するために、上述の方法でかっこを付けるべきである.
  • 副作用付きマクロパラメータ
  • #define MAX(a, b)  ( (a) > (b) ? (a) : (b) )
  • ... x = 5; y = 8; z = MAX(x++, y++); printf("x=%d y=%d z=%d", x, y, z);//出力の結果は何ですか?
  • ここでは、プリプロセッサ処理後の結果が何であるかを知る必要があります.z=((x+)>(y++)?(x++) : (y++));
  • だから出力結果はx=6 y=10 z=9
  • である.
  • #define置換ステップ
  • プログラムにおいて#define定義符号およびマクロを拡張する場合には、いくつかのステップ
  • がある.
  • マクロを呼び出すとき、まずパラメータをチェックして、#defineによって定義された記号が含まれているかどうかを確認します.もしあれば、彼らはまず
  • に置き換えられます.
  • 置換テキストは、その後、プログラム内の元のテキスト位置に挿入される.マクロの場合、パラメータ名はその値に置き換えられます.
  • 最後に、結果ファイルを再度スキャンして、#defineで定義された記号が含まれているかどうかを確認します.ある場合は、上記の手順
  • を繰り返す.
  • 注意:マクロパラメータとdefine定義には、他のdefineポイント翻訳の変数が表示されますが、マクロについては再帰は表示されません.プリプロセッサがdefineで定義する記号を検索する場合、文字列定数の内容は
  • 検索されない.
  • マクロの中の#と##の作用
  • #の役割:マクロパラメータを文字列に変更する
     
    int i = 10;
    #define PRINT(FORMAT, VALUE)\
            printf("the value of "#VALUE" is "FORMAT 
    ", VALUE); PRINT("%d", i+3);
  • コードのVALUEは「VALUE」として前処理され、最終出力の結果はthe value of i+3 is 13
  • となる.
    ##の役割
  • ###の役割は、その両側に位置する記号を1つの記号
  • に合成することである.
  • は、マクロ定義が、分離されたテキストセグメントから識別子
  • を作成することを可能にする.
  • #define ADD_TO_SUM(num, value)
        sum##num += value;
    
    
    ADD_TO_SUM(5, 10); //     sum5 10

  • 3.マクロと関数の比較
  • 関数
  • マクロ比関数はプログラムの規模と速度の面で
  • より優れている.
  • 関数のパラメータは特定のタイプとして宣言する必要があります.したがって、関数はタイプの適切な式でのみ使用できます.しかし、マクロは、整数型、長整数型、浮動小数点型などのタイプを比較するために使用することができる.マクロはタイプに関係のない
  • です.
  • マクロ
  • マクロを使用するたびに、マクロ定義のコードがコードに挿入され、コードが大幅に増加します.マクロが短い場合は
  • マクロはデバッグできません
  • マクロはタイプに関係なく、長所であり短所であり、厳密ではない
  • マクロは少し注意しないと演算子の優先度の問題をもたらし、プログラムエラー
  • を招きやすい.
  • 命名規則
  • マクロ名はすべて大文字で、関数名はすべて大文字ではありません
    4.マクロおよびコマンドライン定義の削除
  • マクロ
  • を削除
  • #undef name
  • この命令は、マクロ定義を削除するために使用される.すなわち、既存の名前を再定義する必要がある場合、古い名前はまず
  • 削除される.
  • コマンドライン定義
  • 多くのCのコンパイラは、コマンドラインでシンボルを定義できる機能を提供します.コンパイルプロセスを開始するための
  • 例えば、同じソースファイルに基づいて異なるプログラムの異なるバージョンをコンパイルする場合、この特性は少し役に立ちます.(プログラムに長さの配列が宣言されていると仮定します.マシンメモリが限られている場合は、小さな配列が必要ですが、別のマシンメモリが大文字である場合は、大文字で書く配列が必要です.)
    #include  
    int main() 
    {   
         int array [ARRAY_SIZE];    
         int i = 0;    
        for(i = 0; i< ARRAY_SIZE; i ++)   
         {        
            array[i] = i;   
         }    
        for(i = 0; i< ARRAY_SIZE; i ++)    
        {        
                printf("%d " ,array[i]);    
        }    
        printf("
    " ); return 0; } // : gcc -DARRAY_SIZE=10 programe.c