次のマクロは問題を引き起こす可能性がありますか?
#define sq(x) x*x
はいの場合、その方法と理由を教えてください。
はい、問題が発生する可能性があります。マクロが名前空間をまったく尊重しないという明らかな事実(つまり、他に何も呼び出せないことを意味しますsq
)を除いて、次のことを試してください。
int result = sq(4) / sq(4);
x * x
かっこで囲む必要があり((x) * (x))
ます。
別の問題:
int a = 0;
int result = sq(++a);
これはマクロに固有の問題であり、インライン関数が優先される理由の1つです。
私はあなたに正解を与えるつもりはありません(これは宿題の質問のように見えます)が、うまくいけばあなたがそれについて考えて正しい答えを思い付くようになる例をあなたに与えるつもりです:
#include <iostream>
#define sq_macro(x) x * x
int sq_function(int x)
{
return x * x;
}
int print_and_ret(int x)
{
std::cout << x << '\n';
return x;
}
int main()
{
std::cout << "Calling sq_macro:\n";
sq_macro(print_and_ret(10));
std::cout << "Calling sq_function:\n";
sq_function(print_and_ret(10));
}
プログラムを実行すると、マクロと関数は2つの異なる動作をします。マクロとは何か、関数とは何かを考えてください。
マクロを作成するときは、角かっこを過度に使用します。マクロを次のように書き直します
#define sq(x) ((x)*(x))
これを行わないと、マクロが次のように使用される場合に問題が発生します。sq(5+4)
問題を理解するには、マクロ展開を実行してを参照してください。
指摘したように、引数が次のようなものである場合など、正しい動作を保証するために、引数の各使用を括弧で囲む必要がありますi * 2
。
#define sq(x) ((x)*(x))
しかし、別の潜在的な問題があります。次のことを考慮してください。
result = sq(++i);
これは次のように翻訳されます。
result = ((++i)*(++i))
意図はi
1回だけ増加する可能性が高いのに対し、2回増加します。これは、マクロの一般的な副作用です。
1つのアプローチは、呼び出すときにこれを認識することですが、より良い方法はsq()
、独自のインライン関数を組み込むことです。
1つは、演算子の優先順位がめちゃくちゃになることです。
sq(2+2); // author wants 4*4, but gets 2+2*2+2.
これらはすべて問題を引き起こす可能性があります。
int x = 12;
int n = sq(x+3);
int y = sq(x++);
int z = 2 * sq(2 + n) * n;
関数と比較してsq
。