回答:
プリプロセッサマクロは、コードに適用される単なる置換パターンです。これらは、コンパイルが始まる前に展開で置き換えられるため、コードのほぼどこでも使用できます。
インライン関数は、本体が呼び出しサイトに直接挿入される実際の関数です。これらは、関数呼び出しが適切な場合にのみ使用できます。
ここで、関数のようなコンテキストでマクロとインライン関数を使用する限り、次のことに注意してください。
まず、プリプロセッサマクロは、コンパイル前のコードに "コピーペースト"するだけです。したがって、型チェックは行われず、いくつかの副作用が発生する可能性があります
たとえば、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); }
max(fibonacci(100), factorial(10000))
大きい方が2回計算されることを考慮してください:(
インライン関数はコンパイラーによって展開されますが、マクロはプリプロセッサーによって展開されるため、単なるテキスト置換です。したがって、
マクロの呼び出し中に型チェックは行われませんが、関数の呼び出し中に型チェックが行われます。
引数の再評価と演算の順序が原因で、マクロ展開中に望ましくない結果と非効率が発生する可能性があります。例えば
#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キーワードをマクロで使用して値を返すことはできません。
インライン関数はオーバーロード可能
マクロに渡されたトークンは、トークン貼り付け演算子と呼ばれる演算子##を使用して連結できます。
マクロは通常、コードの再利用に使用されます。インライン関数は、関数呼び出し中の時間オーバーヘッド(余分な時間)を排除するために使用されます(サブルーチンへのジャンプを回避します)。
マクロは名前空間を無視しています。そして、それは彼らを邪悪なものにします。
インライン関数はマクロに似ています(関数コードはコンパイル時に呼び出し時に展開されるため)、インライン関数はコンパイラーによって解析されますが、マクロはプリプロセッサーによって展開されます。その結果、いくつかの重要な違いがあります。
場合によっては、マクロに引数として渡された式を複数回評価できます。 http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx
マクロはプリコンパイル時に展開され、デバッグには使用できませんが、インライン関数は使用できます。
- 良い記事:http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1
;
インライン関数は値のセマンティクスを維持しますが、プリプロセッサマクロは構文をコピーするだけです。引数を複数回使用すると、プリプロセッサマクロで非常に微妙なバグが発生する可能性があります。たとえば、引数に「i ++」のようなミューテーションが2回実行されている場合は、驚きです。インライン関数にはこの問題はありません。
マクロとインライン関数の違いを知るには、まずそれらが正確に何であり、いつ使用すべきかを知る必要があります。
機能:
int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
関数呼び出しにはオーバーヘッドが関連付けられています。関数の実行が終了した後、関数はどこに戻る必要があるかを知る必要があり、スタックメモリに値を格納する必要があるためです。
小さなアプリケーションの場合は問題ありませんが、毎秒数千のトランザクションが発生する金融アプリケーションの例を考えてみましょう。関数呼び出しを使用することはできません。
マクロ:
# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
int結果= Square(x * x)
しかし、マクロにはそれに関連するバグがあります。
#define Square(x) x*x
int main() {
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
ここでは、出力は36ではなく11です。
インライン関数:
inline int Square(int x) {
return x * x;
}
int main() {
using namespace std;
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
出力36
インラインキーワードは、関数呼び出しを関数の本文で置き換えるようコンパイラーに要求します。ここでは、最初に式が評価されてから渡されるため、出力は正しいです。戻りアドレスとスタックを格納する必要がないため、関数呼び出しのオーバーヘッドが削減されます。関数の引数にメモリは必要ありません。
マクロとインライン関数の比較:
結論:
インライン関数は、パフォーマンスを向上させ、安全に使用でき、関数呼び出しのオーバーヘッドも削減されるため、マクロよりも役立つ場合があります。これは単にコンパイラーへのリクエストであり、特定の関数は次のようにインライン化されません。
これは良いことです。なぜなら、コンパイラが別の方法で物事を行うのが最善であると考えるときはいつでもです。
GCC(他の人についてはよくわかりません)では、関数をインラインで宣言することはコンパイラーへのヒントにすぎません。それが呼び出されるときはいつでも、それが関数の本体を含むかどうかを決定するのは、結局のところ、コンパイラー次第です。
インライン関数とプリプロセッサマクロの違いは比較的大きいです。プリプロセッサマクロは、結局のところ、単なるテキスト置換です。コンパイラが引数と戻り値の型のチェックを実行する機能の多くをあきらめます。引数の評価は大きく異なります(関数に渡す式に副作用がある場合は、デバッグがとても楽しいでしょう)。関数とマクロを使用できる場所については微妙な違いがあります。たとえば、私が持っていた場合:
#define MACRO_FUNC(X) ...
MACRO_FUNCは明らかに関数の本体を定義します。関数を使用できるすべてのケースで正しく実行されるように、特別な注意が必要です。たとえば、MACRO_FUNCが正しく記述されていないと、エラーが発生します。
if(MACRO_FUNC(y)) {
...body
}
通常の機能は問題なく使用できます。
インライン関数は、その中に反復または再帰ステートメントが存在する場合、関数呼び出しとして動作し、命令の繰り返し実行を防止します。プログラム全体のメモリを節約することは非常に役立ちます。
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{
return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases.
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
return a*a*a;
}
int main()
{
cout<<NUMBER<<endl<<number()<<endl;
cout<<CUBE(1+3); //Unexpected output 10
cout<<endl<<cube(1+3);// As expected 64
return 0;
}
マクロは実際の関数呼び出しのオーバーヘッドを含まないため、通常、関数よりも高速です。
マクロの短所:型のチェックがありません。単純な置換が行われるためデバッグが困難です。マクロには名前空間がないため、コードの1つのセクションのマクロが他のセクションに影響を与える可能性があります。上記のCUBE()の例に示すように、マクロは副作用を引き起こす可能性があります。
マクロは通常、1つのライナーです。ただし、複数行で構成することもできます。関数にはそのような制約はありません。
#define TWO_N(n) 2 << n
当時とcout << CUBE(TWO_N(3 + 1)) << endl;
?(出力の行は、出力endl
を開始するよりも終了する方が適切です。)