14

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

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

インライン関数の代わりに。初心者の質問で申し訳ありませんが、この場合、マクロの何がそんなに悪いのでしょうか?

4

8 に答える 8

8

他の回答のほとんどは、例に一般的なマクロの使用上の欠陥がある方法など、マクロが悪である理由について説明しています。Stroustrup の意見は次のとおりです: http://www.research.att.com/~bs/bs_faq2.html#macro

しかし、あなたの質問は、マクロがまだ何に適しているかということでした。マクロがインライン関数よりも優れている場合がいくつかあります。それは、次のようなインライン関数では単純に実行できないことを行う場合です。

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

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

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

于 2009-10-29T00:07:10.830 に答える
7

マクロには、厳密に悪い点がいくつかあります。

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

彼らは通常の意味で議論をしません。int2 つの値を取り、最大値を返す関数を作成できます。これは、引数が 1 回評価され、その後に値が使用されるためです。少なくとも 1 つの引数を 2 回評価し、max(x++, --y).

よくある落とし穴もあります。それらの中に複数のステートメントを入れるのは難しく、余計な括弧がたくさん必要になります。

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

#define radian2degree(a) (a * 57.295779513082)

する必要があります

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

radian2degreeそして、その定義が独自のスコープで機能すると確信して、内部スコープで関数を作成する人をまだ踏んでいます。

于 2009-10-28T22:07:45.887 に答える
7

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

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;

これは期待される結果です。

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

編集

これに関する追加の議論を見ることができますhere

于 2009-10-28T21:55:16.160 に答える
2

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

  • マクロを使用すると、1 + 1 * 57.29... = 58.29... に展開されます。
  • 関数を使用すると、それはあなたが望むもの、つまり (1 + 1) * 57.29... = ... になります。

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

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

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

于 2009-10-28T22:05:10.797 に答える
2

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

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

于 2009-10-28T21:54:41.483 に答える
1

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

于 2009-10-28T22:06:27.970 に答える
0

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

于 2009-10-28T21:57:08.687 に答える
0

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

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

于 2009-10-28T21:58:16.063 に答える