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をご利用ください。
(…まだ説明してませんでした、構造体の時にでも解説します)