9.プリプロセッサとメイクファイル

9-8. マクロ展開

今日からは少しもどってプリプロセッサの続きです。
前回まで #include に始まり、それから分割コンパイル・make と進んで参りました。
今回からは #define の解説です。
#define は定義した文字の変換をします。

例えば

#define PRINT printf

と定義します。
すると、ソースプログラム中の PRINT はすべて printf に変換されます。

#include<stdio.h>
#define PRINT printf

main()
{
    PRINT("It's macro.\n");
}

ちゃんと PRINT が printf として使えたと思います。
次に、値に対して文字を割り当ててみます。

#define TRUE 1
#define FALSE 0

もっともこれらの定義は stdio.h 等にしてある可能性はありますが念のため定義しておきます。
そうするとプログラム中の処理で成功・失敗を処理する時の表現が分かりやすいものになります。

if(check==FALSE){ /* この使い方は少ない、if(!check)の方がメジャー */
printf(“処理失敗、プログラムを強制終了します。\n”);
return FALSE ;
}

あとTRUEの場合などは

while(TRUE) /* while(1) に同じ…無限ループ */

のような使い方があります。
さらに、#define では引数を入れることにより関数式を定義することもできます。

例:#define DOUBLE(x) x+x

ソース中に DOUBLE(5) と書くと、5+5 に変換されます。

注意!
あくまで #define は文字の変換です。

#include<stdio.h>
#define DOUBLE(x) x + x 

main()
{
    int x;
    x = DOUBLE(4) * DOUBLE(6);
    printf("%d\n",x);
}

とプログラムを組んだ場合、4 + 4 * 6 + 6 となり、優先順位が変わってしまって x は34になってしまいます。
これでは関数としての働きがありません。
そうならないためにも、優先順位が変わらないように(括弧)で囲んでください

#define DOUBLE(x) x + x /* 悪い例 */
#define DOUBLE(x) (x + x) /* これでも、数式が引数として渡されたら危険 */
#define DOUBLE(x) ((x) + (x)) /* よい例 */

2番目の数式が渡せれたら危険という例を下に示します。

#include<stdio.h>
#define square(x) (x * x) 

main()
{
    int x;
    x = square(3+4);
    printf("%d\n",x);
}

答えは49ではなく19になってしまいます。
これもsquare(3+4)が、(3+4*3+4)となるためです。
これを

#define square(x) ((x) * (x))

と定義すればsquare(3+4)は、ちゃんと((3+4)*(3+4))になります。

※最後に型を定義する時の注意
#defineを使えば、const unsigned long int のような長いものも単純にできますが、typedef という型の定義をする予約語ああリます。

こちらのほうが安全性が高いので型の定義についてはtypedefをご利用ください。
(…まだ説明してませんでした、構造体の時にでも解説します)