インライン関数の代わりにマクロを使用する必要があるのはいつですか?

StackOverflow https://stackoverflow.com/questions/1640344

  •  08-07-2019
  •  | 
  •  

質問

以前の質問良い答えだと思ったものは、提案されたマクロの使用に対して投票されました

#define radian2degree(a) (a * 57.295779513082)
#define degree2radian(a) (a * 0.017453292519)

インライン関数の代わり。初心者の質問はご容赦ください。ただし、この場合のマクロの悪さは何ですか?

役に立ちましたか?

解決

マクロについては、いくつかの厳密に悪いことがあります。

これらはテキスト処理であり、スコープはありません。 #define foo 1 の場合、その後の foo の識別子としての使用は失敗します。これにより、奇妙なコンパイルエラーや見つけにくいランタイムバグが発生する可能性があります。

通常の意味での引数は取りません。 2つの int 値を取り、最大値を返す関数を作成できます。これは、引数が1回評価され、その後値が使用されるためです。少なくとも1つの引数を2回評価し、 max(x ++、--y)などのエラーで失敗するため、マクロを作成することはできません。

よくある落とし穴もあります。それらの中に複数のステートメントを正しく入れることは難しく、それらには多くの不必要な括弧が必要です。

あなたの場合、括弧が必要です:

#define radian2degree(a) (a * 57.295779513082)

する必要があります

#define radian2degree(a) ((a) * 57.295779513082)

そして、あなたはまだその内側のスコープで関数 radian2degree を書いている人を踏んでいるので、その定義がそれ自身のスコープで動作することを確信しています。

他のヒント

他の回答のほとんどは、マクロが悪である理由を説明します。たとえば、サンプルに一般的なマクロ使用の欠陥があることも含まれます。 Stroustrupの見解: http://www.research.att.com/~bs /bs_faq2.html#macro

しかし、あなたの質問は、どのマクロがまだ良いのかを尋ねることでした。インライン関数よりもマクロの方が優れている点がいくつかあります。それは、次のようなインライン関数では単純にできないことをしているところです。

  • トークンの貼り付け
  • 行番号などの処理( assert()でのエラーメッセージの作成など)
  • 式ではないものを扱う(たとえば、 offsetof()の実装が型名を使用してキャスト操作を作成する数)
  • 配列要素の数を取得するマクロ(配列名がポインタに簡単に減衰するため、関数では実行できません)
  • テンプレートが利用できないCで「型多態性」関数のようなものを作成する

しかし、インライン関数を持つ言語では、マクロのより一般的な使用は必要ないはずです。インライン関数をサポートしていないCコンパイラを扱っているときは、マクロを使用することすら嫌がります。そして、可能な限り、タイプに依存しない関数を作成するためにそれらを使用しないようにします(代わりに、名前の一部としてタイプインジケーターを持ついくつかの関数を作成します)。

#define の代わりに、名前付き数値定数に列挙型を使用するようになりました。

この特定のマクロについて、次のように使用する場合:

int x=1;
x = radian2degree(x);
float y=1;
y = radian2degree(y);

型チェックは行われず、x、yには異なる値が含まれます。

さらに、次のコード

float x=1, y=2;
float z = radian2degree(x+y);

に変換されるので、あなたが考えていることはしません

float z = x+y*0.017453292519;

の代わりに
float z = (x+y)+0.017453292519;

これは予想される結果です。

これらは、マクロの誤用と誤用のほんの一例です。

編集

このこちら

マクロは比較的頻繁に悪用され、例に示すようにマクロを使用すると簡単にミスを犯す可能性があります。式radian2degree(1 + 1)を使用します。

  • マクロを使用すると、1 + 1 * 57.29 ... = 58.29 ...に展開されます
  • 関数を使用すると、(1 + 1)* 57.29 ... = ...
  • になります

より一般的には、マクロは関数のように見えるため悪意があります。したがって、マクロは関数のようにだまされます微妙なルールがあります。この場合、正しい書き方は次のとおりです(aの周りの括弧に注意してください):

#define radian2degree(a) ((a) * 57.295779513082)

ただし、インライン関数に固執する必要があります。邪悪なマクロとその微妙さの例については、C ++ FAQ Liteからのこれらのリンクを参照してください。

可能であれば、常にインライン関数を使用します。これらはタイプセーフであり、簡単に再定義することはできません。

定義は未定義に再定義でき、型チェックはありません。

コンパイラのプリプロセッサはひどいものなので、巧妙なトリックの恐ろしい候補です。他の人が指摘しているように、コンパイラがマクロとあなたの意図を誤解しやすく、マクロが実際に行うことを誤解しやすいですが、最も重要なことは、デバッガでマクロにステップインできないことです!

マクロは、変数またはスカラー以上のものを渡すことになり、これは望ましくない動作で解決する可能性があるため、悪です(maxマクロを定義してaとbの間の最大値を決定しますが、a ++とb ++をマクロに渡し、何が起こるかを見てください。)

とにかく関数がインライン化される場合、関数とマクロの間にパフォーマンスの違いはありません。ただし、関数とマクロにはいくつかの使いやすさの違いがあり、そのすべてが関数の使用に有利です。

マクロを正しくビルドすれば、問題はありません。ただし、関数を使用する場合、コンパイラーは毎回正しく実行します。したがって、関数を使用すると、不正なコードを書くのが難しくなります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top