1. ホーム
  2. c

[解決済み] C言語におけるマクロと関数の比較

2022-02-11 02:26:55

質問

関数を使うよりマクロを使った方がいいというケースをよく見かけます。

関数と比較した場合のマクロのデメリットを、例を挙げて説明してください。

どのように解決するのですか?

マクロは、テキストによる置換に依存し、型チェックを行わないため、エラーが発生しやすい。例えば、このマクロ。

#define square(a) a * a

は整数で使用しても問題なく動作します。

square(5) --> 5 * 5 --> 25

が、式と一緒に使うと非常に奇妙なことになります。

square(1 + 2) --> 1 + 2 * 1 + 2 --> 1 + 2 + 2 --> 5
square(x++) --> x++ * x++ --> increments x twice

引数を括弧で囲むことは有効ですが、これらの問題が完全になくなるわけではありません。

マクロが複数のステートメントを含んでいる場合、コントロールフロー構造でトラブルになることがあります。

#define swap(x, y) t = x; x = y; y = t;

if (x < y) swap(x, y); -->
if (x < y) t = x; x = y; y = t; --> if (x < y) { t = x; } x = y; y = t;

これを解決するための通常の戦略は、ステートメントを "do { ... の中に入れることです。} while (0)" ループの中に記述することです。

同じ名前で異なるセマンティクスを持つフィールドを含む2つの構造体がある場合、同じマクロが両方に対して動作し、奇妙な結果になる可能性があります。

struct shirt 
{
    int numButtons;
};

struct webpage 
{
    int numButtons;
};

#define num_button_holes(shirt)  ((shirt).numButtons * 4)

struct webpage page;
page.numButtons = 2;
num_button_holes(page) -> 8

最後に、マクロはデバッグが難しく、奇妙な構文エラーや実行時エラーが発生し、理解するために展開する必要があります(例:gcc -E)、この例のように、デバッガはマクロをステップスルーできないからです。

#define print(x, y)  printf(x y)  /* accidentally forgot comma */
print("foo %s", "bar") /* prints "foo %sbar" */

インライン関数と定数は、マクロのこれらの問題の多くを回避するのに役立ちますが、常に適用できるわけではありません。マクロを使用して意図的に多相性の動作を指定した場合、意図しない多相性を回避することが困難な場合があります。C++には、マクロを使わずに型安全な方法で複雑な多相構造を作成するのに役立つテンプレートなどの機能があります; Stroustrupの C++プログラミング言語 をご覧ください。