C++マクロ
10803 ワード
転載:https://blog.csdn.net/shuzfan/article/details/52860664
——————#define基本用法——————
#defineコマンドは、C言語のマクロ定義コマンドで、マクロ名と定義された識別子(マクロ名)を置換テキストと呼ぶ文字列として定義します.プログラムがコンパイルされる前に、コンパイル時にすべてのマクロ名が定義された文字列に置き換えられます.これがマクロ置換です.
マクロ定義を理解する鍵は、「置換」にあります.
このコマンドには、単純なマクロ定義とパラメータ付きマクロ定義の2つのフォーマットがあります.
(1)簡単なマクロ定義:#define
例:#define PI 3.14プログラム:
1
(2)パラメータ付きマクロ定義#define()
例:#define AddOne(x)(x+1)プログラム:
1
2
——————————マクロ置換が起こったタイミング——————
defineの役割を本当に理解するために、C言語ソースプログラムの処理手順を理解してみましょう.Turbo Cのような統合された開発環境で作成されたソースプログラムをコンパイルすると、実際には、前処理、コンパイル、アセンブリ、接続のいくつかのプロセスが行われます.プリプロセッサは、次の機能を実現するコンパイラの出力を生成します.
(1)ファイルに含む
ソースプログラムのincludeをファイル本文、すなわち含むものに拡張することができる.hファイルが見つかり、#includeの場所に展開されます.
(2)条件コンパイル
プリプロセッサは、#ifや#ifdefなどのコンパイルコマンドとその後の条件に従って、ソースプログラムの一部を含めたり除外したりして、通常は除外された文を空行に変換します.
(3)マクロ展開
プリプロセッサは、ソース・プログラム・ファイルに表示されるマクロへの参照を対応するマクロ定義、すなわち、本明細書で説明するdefineの機能に展開し、プリプロセッサによって完了する.プリプロセッサ処理されたソースプログラムは、以前のソースプログラムとはすべて異なり、この段階で行われる作業は純粋な置き換えと展開にすぎず、計算機能がないため、#defineコマンドを学習する際にこれを本当に理解できれば、このコマンドに誤解や誤用を招くことはありません.
————————マクロ置換エラーの例——————
「直接置換」を厳守すれば、次のような問題は起こりません.
たとえば、次のマクロ定義があります.
1
2
3
4
5
6
————————マクロ定義の特徴——————
(1)マクロ名は一般に大文字で,末尾にセミコロンを付けない.
(2)マクロ定義のパラメータはタイプがなく,構文チェックを行わず,式解を行わず,置換のみを行う.
(3)マクロ定義は通常ファイルの先頭にあり,使用可能である.
1
コマンドは、マクロ定義の役割ドメインを終了します.
(4)マクロ定義はネストできますが、文字列""にはマクロは含まれません.
(5)マクロ展開はソースプログラムを長くし、関数呼び出しはできない.マクロ展開は実行時間を占めず、コンパイル時間のみを占め、関数呼び出しは実行時間を占める(メモリの割り当て、フィールドの保持、値の伝達、戻り値).
(6)関数呼び出しはコンパイル後のプログラム実行時に行われ、メモリが割り当てられる.マクロ置換はコンパイル前に行われ、メモリは割り当てられない.
(7)マクロを使用すると、プログラムの汎用性と読みやすさが向上し、不一致性が減少し、入力エラーが減少し、修正が容易になります.たとえば、配列サイズはマクロ定義、定数piはマクロ定義を常用します.
——————defineの3つの特殊記号:##,#,#@————
1
2
3
4
5
6
7
8
9
10
————————常用マクロ定義——————
(1)1つのヘッダファイルが重複して含まれることを防止する
1
2
3
4
5
6
(2)指定されたアドレス上の1バイトまたはワードを得る
1
2
3
4
5
6
7
8
9
(3)構造体(struct)におけるfieldのオフセット量を得る
1
(4)1つの構造体におけるfieldが占有するバイト数を得る
1
(5)1変数のアドレス(word幅)を得る
1
2
3
(6)1文字を大文字に変換
1
(7)オーバーフロー防止の1つの方法
1
(8)配列要素を返す個数
1
(9)いくつかのマクロ追跡デバッグを使用する
ANSI規格は、5つの定義済みマクロ名を示している.これらは次のとおりです.
__LINE__:ソースコードに現在のソースコード行番号を挿入します.
__FILE__:現在のソースファイル名をソースファイルに挿入します.
__DATE__:ソースファイルに現在のコンパイル日を挿入
__TIME__:ソースファイルに現在のコンパイル時間を挿入します.
__stdC__:この識別は、プログラムがANSI C規格に厳格に従うことが要求される場合、1に割り当てられる.
__cplusplus:C++プログラムを記述するときにこの識別子が定義される
——————#define基本用法——————
#defineコマンドは、C言語のマクロ定義コマンドで、マクロ名と定義された識別子(マクロ名)を置換テキストと呼ぶ文字列として定義します.プログラムがコンパイルされる前に、コンパイル時にすべてのマクロ名が定義された文字列に置き換えられます.これがマクロ置換です.
マクロ定義を理解する鍵は、「置換」にあります.
このコマンドには、単純なマクロ定義とパラメータ付きマクロ定義の2つのフォーマットがあります.
(1)簡単なマクロ定義:#define
例:#define PI 3.14プログラム:
float pi2 = PI * 2;//pi2 = 6.28
1
(2)パラメータ付きマクロ定義#define()
例:#define AddOne(x)(x+1)プログラム:
float pi2 = PI * 2;//pi2 = 6.28
pi2 = AddOne(pi2);// pi2 = 7.28
1
2
——————————マクロ置換が起こったタイミング——————
defineの役割を本当に理解するために、C言語ソースプログラムの処理手順を理解してみましょう.Turbo Cのような統合された開発環境で作成されたソースプログラムをコンパイルすると、実際には、前処理、コンパイル、アセンブリ、接続のいくつかのプロセスが行われます.プリプロセッサは、次の機能を実現するコンパイラの出力を生成します.
(1)ファイルに含む
ソースプログラムのincludeをファイル本文、すなわち含むものに拡張することができる.hファイルが見つかり、#includeの場所に展開されます.
(2)条件コンパイル
プリプロセッサは、#ifや#ifdefなどのコンパイルコマンドとその後の条件に従って、ソースプログラムの一部を含めたり除外したりして、通常は除外された文を空行に変換します.
(3)マクロ展開
プリプロセッサは、ソース・プログラム・ファイルに表示されるマクロへの参照を対応するマクロ定義、すなわち、本明細書で説明するdefineの機能に展開し、プリプロセッサによって完了する.プリプロセッサ処理されたソースプログラムは、以前のソースプログラムとはすべて異なり、この段階で行われる作業は純粋な置き換えと展開にすぎず、計算機能がないため、#defineコマンドを学習する際にこれを本当に理解できれば、このコマンドに誤解や誤用を招くことはありません.
————————マクロ置換エラーの例——————
「直接置換」を厳守すれば、次のような問題は起こりません.
たとえば、次のマクロ定義があります.
#define Square(x) x*x
float temp = Square(3+3);
// 6*6=36, , , 3+3*3+3=15
// , :
#define Square(x) ((x)*(x))
1
2
3
4
5
6
————————マクロ定義の特徴——————
(1)マクロ名は一般に大文字で,末尾にセミコロンを付けない.
(2)マクロ定義のパラメータはタイプがなく,構文チェックを行わず,式解を行わず,置換のみを行う.
(3)マクロ定義は通常ファイルの先頭にあり,使用可能である.
#undef
1
コマンドは、マクロ定義の役割ドメインを終了します.
(4)マクロ定義はネストできますが、文字列""にはマクロは含まれません.
(5)マクロ展開はソースプログラムを長くし、関数呼び出しはできない.マクロ展開は実行時間を占めず、コンパイル時間のみを占め、関数呼び出しは実行時間を占める(メモリの割り当て、フィールドの保持、値の伝達、戻り値).
(6)関数呼び出しはコンパイル後のプログラム実行時に行われ、メモリが割り当てられる.マクロ置換はコンパイル前に行われ、メモリは割り当てられない.
(7)マクロを使用すると、プログラムの汎用性と読みやすさが向上し、不一致性が減少し、入力エラーが減少し、修正が容易になります.たとえば、配列サイズはマクロ定義、定数piはマクロ定義を常用します.
——————defineの3つの特殊記号:##,#,#@————
/*x y, :int n = Conn(123,456); n=123456;char* str = Conn("asdf", "adf"); /* str = "asdfadf";*/
#define Conn(x,y) x##y
/* x , const char。 :char a = ToChar(1); a='1'; char a = ToChar(123); ; , !error C2015: too many characters in constant :P */
#define ToChar(x) #@x
// x , :char* str = ToString(123132); str="123132";
#define ToString(x) #x
1
2
3
4
5
6
7
8
9
10
————————常用マクロ定義——————
(1)1つのヘッダファイルが重複して含まれることを防止する
#ifndef BODYDEF_H
#define BODYDEF_H
//
#endif
1
2
3
4
5
6
(2)指定されたアドレス上の1バイトまたはワードを得る
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
// :
int bTest = 0x123456;
byte m = MEM_B((&bTest));/*m=0x56*/
int n = MEM_W((&bTest));/*n=0x3456*/
1
2
3
4
5
6
7
8
9
(3)構造体(struct)におけるfieldのオフセット量を得る
#define OFFSETOF( type, field ) ( (size_t) &(( type *) 0)-> field )
1
(4)1つの構造体におけるfieldが占有するバイト数を得る
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )
1
(5)1変数のアドレス(word幅)を得る
#define B_PTR( var ) ( (byte *) (void *) &(var) )
#define W_PTR( var ) ( (word *) (void *) &(var) )
1
2
3
(6)1文字を大文字に変換
#define UPCASE( c ) ( ((c) >= ''a'' && (c) <= ''z'') ? ((c) - 0x20) : (c) )
1
(7)オーバーフロー防止の1つの方法
#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
1
(8)配列要素を返す個数
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
1
(9)いくつかのマクロ追跡デバッグを使用する
ANSI規格は、5つの定義済みマクロ名を示している.これらは次のとおりです.
__LINE__:ソースコードに現在のソースコード行番号を挿入します.
__FILE__:現在のソースファイル名をソースファイルに挿入します.
__DATE__:ソースファイルに現在のコンパイル日を挿入
__TIME__:ソースファイルに現在のコンパイル時間を挿入します.
__stdC__:この識別は、プログラムがANSI C規格に厳格に従うことが要求される場合、1に割り当てられる.
__cplusplus:C++プログラムを記述するときにこの識別子が定義される