インライン関数とプリプロセッサマクロの違いは何ですか?
プリプロセッサマクロは、コードに適用される単なる置換パターンです。これらは、コンパイルの開始前に展開で置き換えられるため、コードのほぼどこでも使用できます。
インライン関数は、その呼び出し元に直接ボディが挿入される実際の関数です。関数呼び出しが適切な場合にのみ使用できます。
ここで、関数のようなコンテキストでマクロとインライン関数を使用する限り、次の点に注意してください。
まず、プリプロセッサマクロは、コンパイル前のコード内の「コピーペースト」です。したがって、型チェックはなく、一部の副作用が表示される可能性があります
たとえば、2つの値を比較する場合:
_#define max(a,b) ((a<b)?b:a)
_
たとえば、max(a++,b++)
を使用すると、副作用が現れます(a
またはb
は2回インクリメントされます)。代わりに、(たとえば)を使用します
_inline int max( int a, int b) { return ((a<b)?b:a); }
_
インライン関数はコンパイラによって展開されますが、マクロはプリプロセッサによって展開されますが、これは単なるテキストの置換です。
関数呼び出し中に型チェックが行われている間、マクロ呼び出し中の型チェックはありません。
引数の再評価と操作の順序のために、マクロ展開中に望ましくない結果と非効率が発生する場合があります。例えば
#define MAX(a,b) ((a)>(b) ? (a) : (b))
int i = 5, j = MAX(i++, 0);
結果として
int i = 5, j = ((i++)>(0) ? (i++) : (0));
マクロ引数は、マクロ展開の前に評価されません
#define MUL(a, b) a*b
int main()
{
// The macro is expended as 2 + 3 * 3 + 5, not as 5*8
printf("%d", MUL(2+3, 3+5));
return 0;
}
// Output: 16`
関数の場合のように、returnキーワードをマクロで使用して値を返すことはできません。
インライン関数はオーバーロードできます
マクロに渡されるトークンは、トークン貼り付け演算子と呼ばれる演算子##を使用して連結できます。
通常、マクロはコードの再利用に使用され、インライン関数を使用して、関数呼び出し中の時間オーバーヘッド(余分な時間)を排除します(サブルーチンへのジャンプを回避します)。
主な違いは型チェックです。コンパイラーは、入力値として渡すものが関数に渡すことができるタイプであるかどうかをチェックします。これはプリプロセッサマクロには当てはまりません。マクロは型チェックの前に展開されるため、深刻で困難なバグを検出できます。
ここ は、その他のいくつかの明らかでない点を概説しています。
すでに指定されているものに別の違いを追加するには、#define
はデバッガーで使用できますが、インライン関数をステップ実行できます。
マクロは名前空間を無視しています。そして、それは彼らを悪にします。
インライン関数はマクロに似ています(コンパイル時に呼び出しの時点で関数コードが展開されるため)、インライン関数はコンパイラーによって解析されますが、マクロはプリプロセッサーによって展開されます。その結果、いくつかの重要な違いがあります。
場合によっては、マクロに引数として渡された式を複数回評価できます。 http://msdn.Microsoft.com/en-us/library/bf6bf4cf.aspx
マクロはプリコンパイル時に展開され、デバッグには使用できませんが、インライン関数は使用できます。
-良い記事:http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1 =
;
インライン関数は値のセマンティクスを維持しますが、プリプロセッサマクロは構文をコピーするだけです。引数を複数回使用すると、プリプロセッサマクロで非常に微妙なバグが発生する可能性があります。たとえば、引数に「i ++」のような2回実行する突然変異が含まれている場合は非常に驚きです。インライン関数にはこの問題はありません。
インライン関数は、通常の関数と同じように構文的に動作し、メソッドの場合、関数のローカル変数とクラスメンバーへのアクセスに型の安全性とスコープを提供します。また、インラインメソッドを呼び出す場合は、プライベート/保護された制限に従う必要があります。
コーディングの観点から見ると、インライン関数は関数のようなものです。したがって、インライン関数とマクロの違いは、関数とマクロの違いと同じです。
コンパイルの観点から見ると、インライン関数はマクロに似ています。呼び出されるのではなく、コードに直接挿入されます。
一般に、インライン関数は、多少の最適化が混在した通常の関数であると考えてください。ほとんどの最適化と同様に、実際に適用するかどうかを判断するのはコンパイラ次第です。多くの場合、コンパイラはさまざまな理由で、プログラマーによる関数のインライン化の試みを喜んで無視します。
インライン関数は、命令の繰り返し実行を防ぐために、反復文または再帰文が存在する場合、関数呼び出しとして動作します。プログラム全体のメモリを節約するのに非常に役立ちます。
GCC(他のことについてはわかりません)では、関数をインラインで宣言することは、コンパイラーへの単なるヒントです。関数が呼び出されるたびに関数の本体を含めるかどうかを決定するのは、一日の終わりの時点でコンパイラ次第です。
インライン関数とプリプロセッサマクロの違いは比較的大きいです。プリプロセッサマクロは、一日の終わりの単なるテキスト置換です。コンパイラが引数の型チェックをチェックし、型を返すための多くの機能を放棄します。引数の評価は大きく異なります(関数に渡す式に副作用がある場合、非常に楽しいデバッグができます)。関数とマクロを使用できる場所については微妙な違いがあります。たとえば、私が持っていた場合:
#define MACRO_FUNC(X) ...
MACRO_FUNCは明らかに関数の本体を定義します。関数を使用できるすべての場合に正しく実行されるように特別な注意が必要です。たとえば、不完全に記述されたMACRO_FUNCは、
if(MACRO_FUNC(y)) {
...body
}
通常の機能は問題なく使用できます。