第30章 マクロの書式

 マクロは非常に便利ですが、使い方を心得ておかなければマクロ特有のバグを誘発する危険があります。それを防ぐためには、マクロのことをよく知っておく必要があるでしょう。

 今回は、先ずマクロのいけない書き方を書いて、それから正しい表記について説明するという形式を取ってみたいと思います。


 今回の要点はこんなところです。


 では、いってみましょう。


 早速1個目を見てみましょう。

#define FUNC (name)     void name(int x, int y)

 うわぁ、これはだめですね。だめですが、見つけやすいバグですね。コンパイルエラーになりますから。

 マクロ名と差し込むテキストとを分けるものは「空白」です。ですから、FUNC とカッコとの間をあけて書いてしまうと、例えば FUNC(Func) は

(name)     void name(int x, int y)(Func)

という訳の分からないものになってしまいます。ですから、正しくは

#define FUNC(name)      void name(int x, int y)

となります。

 ただし、引数を取るタイプのもののカッコの内部でスペースを入れるのは構いません。たとえば、

#define FUNC( param1, param2 )    param1(param2)

のとき、FUNC(Func, 1); は Func(1); に正しく置き換えられます。


 では、2個目を見てみましょう。

#define COORDINATE(str, x, y);    sprintf(str, "(%d, %d)", x, y);

 これはどうやら、sprintf を使って、2つの値を座標表記の文字列に変換しようとしているようです。

 しかし、これはタチの悪いバグの1つにあげられます。何故かというと、ある条件の時にのみ異常動作を行うからです。

 どこがいけないかを端的に言うと、セミコロンを付けているのがいけないのです。引数を取る形のマクロでは、カッコの終わりもマクロ名と差し込むテキストの境界になります。つまり、例えば

for(i = 0; i < NUM_COORDINATES; i++)
    COODINATE(str, x[i], y[i]);

は、

for(i = 0; i < NUM_COORDINATES; i++)
    ;    sprintf(str, "(%d, %d)", x[i], y[i]);;

になってしまいます。

 ; は白文と言って、1文として数えられます。なので、NUM_COORDINATES 回ぐるぐると空回りしたあげく、x[NUM_COORDINATES] という訳の分からない値を使用してしまうことになります。もう最悪です。

 これは書き間違いによって起こったバグですが、意図的に複文をマクロにすることもあります。そのようなときは、十分に扱いを注意して下さい。単文か複文か忘れた、もしくはわからないときは、素直に { } で囲むのが賢明かもしれません。


 では、どんどんいってみましょう。次は3個目です。

#define MUL(a, b)                 a * b

 これはまたタチの悪いものが出てきました。上と同じように、正常に動作するときもあるからです。

 これは正しくは

#define MUL(a, b)                 ((a) * (b))

と書かなくてはなりません。

 これで気付いた方もいるでしょう。つまりは、上の書き方だと

cout << MUL(1 + 4, 2 + 8) * 3 << endl;

としても、

cout << 1 + 4 * 2 + 8 * 3 << endl;

となってしまうため、正解の150が表示されずに33が表示されてしまいます。ですが、下の書き方だと

cout << ((1 + 4) * (2 + 8)) * 3 << endl;

となって、150がきちんと表示されます。

 このように、演算子の優先順位を無視した書き方は厳禁です。見栄えが悪くなっても、カッコでゴテゴテに飾って下さい。


 では、4個目に移りましょう。

#define SHOW_ALL_VALUABLES()      cout << "a = " << a << endl
                                       << "b = " << b << endl
                                       << "c = " << c << endl

 これはわかりやすいバグに入りますね。コンパイル自体が通りませんから。

 マクロの定義の終わりの印は改行です。なので、b 以降の部分は取り残されてしまい、エラーになります。

 改行したい時は、行の終わりに \ を付けます。すなわち、正しくは

#define SHOW_ALL_VALUABLES()      cout << "a = " << a << endl \
                                       << "b = " << b << endl \
                                       << "c = " << c << endl

となります。


 あと、細かいことですが、マクロは通例小文字は使いません。使えはしますが、大文字なのがマクロの目印とするのが普通です。


 とりあえず今の知識の範囲内で必要なのはここまでです。本当はもう1つ重要なのがありますが、それはそのときがきたらお話しします。

 では、今回の要点です。


 それでは、さようなら。


第29章 マクロの活用法 | 第31章 メモリとアドレス

Last update was done on 1999.3.31

この講座の著作権はロベールが保有しています