C言語 マクロ定義の使い方

  • このエントリーをはてなブックマークに追加
Pocket

あなたは、配列の要素数や、for文の繰り返し回数などの数値を、直接プログラムに書いていませんか?

もし、そうなら今すぐ、それをやめましょう。

なぜなら、プログラムの意味もわかりにくくなりますし、修正するときに複数個所に及ぶとミスも増えるからです。

そんなときに、便利なのがマクロ定義です。

マクロ定義の仕方

マクロ定義の書き方ですが、例えば、以下のようにすればいいです。

#define MAX 10

これで、「MAX」という文字列は「10」という文字列で定義されたということになります。

したがって、この定義以降、同一ファイル内で、「MAX」と書かれた箇所は「10」に置き換えられます。

大抵の場合、このマクロ定義は大文字で書かれます。小文字でもいいのでしょうが、その場合、通常の変数とマクロ定義との区別がつきにくいでしょう。

MAXというのはあくまで固定データですので、

MAX = 10;

というように、代入することはできません。

また、関数のように宣言することもできます。

#define CALC(a, b) (a + b)

このように定義すると、CALCを記述した箇所は「(a + b)」の演算が行われます。ここで注目してほしいのは、関数と違って、型の指定が不要な点です。

通常の関数は、引数に型を宣言する必要がありますが、マクロ定義の場合は、それが不要というのが特徴です。すなわち、どんな型でもよいということです。

演算だけでなく、条件文もマクロ定義することができます。

#define DIVISION(a, b, ret) \
    if (b == 0) {\
        ret = 32767;\
    } else {\
        ret = a / b;\
    }\

割り算を行うマクロです。「0」では割れないので、条件文を入れました。複数行になる場合は、各行の末尾にバックスラッシュを記述します。

これで、割り算を実行したい箇所に、このマクロを記述すれば、割る数を気にすることなく、プログラムを記述することができます。

マクロ定義の使い方

まず、定数定義のためのマクロですが、以下のように、配列の要素数の定義や、for文の繰り返し回数を定義するのに、よく使われます。

#include <stdio.h>

#define MAX 10

void main(void)
{
    int array[MAX];
    int i;
    int sum;

    printf("データ入力\n");
    for (i = 0; i < MAX; i++) {
        printf("array[%d] = ", i);
        scanf("%d", &array[i]);
    }

    sum = 0;
    for (i = 0; i < MAX; i++) {
        sum += array[i];
    }
    printf("データ合計\n");
    printf("sum = %d\n", sum);
}

配列arrayの要素数は10、for文の繰り返し回数も10となります。

配列の要素数とfor文の繰り返し回数は、for文の処理に配列が関係している場合は、同じになることが多いため、マクロ定義しておくと便利です。

万一、要素数に変更があっても、マクロの定義を変えるだけで済みます。

マクロ定義を記述する位置は、それを使用する箇所より、上部に記述しなくてはいけません。通常は、#inclueの後に書くので、それほど気にする必要はないでしょう。

次に、さきほどの割り算のマクロ定義の使ってみます。

#include <stdio.h>

#define DIVISION(a, b, ret) \
    if (b == 0) {\
        ret = 32767;\
    } else {\
        ret = a / b;\
    }\

void main(void)
{
    double x, y;
    double ans;

    printf("データ入力\n");
    printf("x = ");
    scanf("%lf", &x);
    printf("y = ");
    scanf("%lf", &y);

    /* 割り算を行うマクロ */    
    DIVISION(x, y, ans);

    printf("x / y = %lf\n", ans);
}

マクロは関数ではなく、置き換えになるので、プログラムの見た目は短いかもしれませんが、実際には、マクロ内のif文が展開されます。

したがって、処理速度は失われませんが、いくつも記述すると、プログラムのサイズが大きくなってしまいます。

マクロ定義の注意点

マクロ定義は、便利なので使用するべきですが、もちろん注意しなくてはならない点もありますので、紹介しておきます。

先ほども、お話ししましたが、マクロを使う前に、マクロを定義する必要があります。これは、通常の変数や関数でも同じですよね。

それから、定義したファイルのみしか利用できません。これも変数や関数でも同じですね。ただ、変数や関数は、externを用いれば、利用できます。

マクロはそれもできませんので、もし、その必要があるなら、マクロ定義用のヘッダファイルを作ります。

そこに、マクロ定義を記述します。そして、必要なファイルでヘッダファイルを#includeすれば、複数ファイルでも利用できます。

関数のように定義した割り算のマクロですが、こちらは引数の型は何でもいいことは、お話ししました。

先ほどの例のプログラムを見てもらえれば、わかると思うのですが、関数と使い方が少し違うことに気付いているでしょうか?

第3引数がポインタでないところです。

通常の関数では、ポインタで渡さないと、演算結果が失われますよね。しかし、マクロの場合は、処理の置き換えになるため、ポインタの必要がないのです。

ここが関数とマクロの違いです。

もう一つ、マクロで注意してもらいたいことがあります。先ほど、マクロは処理の置き換えとお伝えしました。

したがって、演算の優先順位、型変換が思わぬ失敗を招くかもしれません。

次の例を見てください。

#include <stdio.h>

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


void main(void)
{
    int x, y;
    int ans;

    printf("データ入力\n");
    printf("x = ");
    scanf("%lf", &x);
    printf("y = ");
    scanf("%lf", &y);

    /* 掛け算 */    
    ans = CALC_MULT(x + 1, y);

    printf("(x + 1) * y = %d\n", ans);
}

「(x + 1) * y」という演算をさせたいと思って、CALC_MULTのマクロを使いました。しかし、これでは正しい結果は得られません。

それは、

ans = x + 1 * y;

となってしまうからです。

カッコ()がついていないために、結果が違ってしまうのです。これを解決するには、

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

とします。これだと、処理の置き換えで、

ans = (x + 1) * (y);

となり、思っている結果が得られます。

まとめ

マクロ定義について、お話ししました。定義の仕方や使い方は、そんなに難しくないと思います。

定数の定義なんかは、マクロ定義を使うことをお勧めします。

そうすることで、可読性、修正時の対応が格段に上がるからです。

処理をマクロにする場合は、注意点さえ気をつければ、十分に有効なので、ぜひ使ってみてください。

ただし、使用個所が多すぎると、プログラムのサイズが大きくなってしまうので、そこだけ気を付けてください。

  • このエントリーをはてなブックマークに追加

コメントを残す

*