第1節で紹介した#define疑似命令は定数を宣言する疑似命令ですが、
実は、それ以上に高度な機能を持ち合わせています。
#define疑似命令による定数は、単なる置き換えによって実現されていますが、
これを利用すると特殊な処理を行わせることも可能です。
例えば、変数の中身を画面に表示するにはprintf文を次のように使用します。
しかし、変数tempの値をあちこちで表示する必要がある場合に、printf("temp = %d\n",temp);
このプログラムの実行結果は、次の通りになります。#include <stdio.h> #define PRINT_TEMP printf("temp = %d\n",temp) int main(void) { int temp = 100; PRINT_TEMP; return 0; }
このプログラムのトリックは、#define疑似命令の定義内容にあります。
temp = 100
この様な使い方で#define疑似命令を乱用するとプログラムがわかりにくくなりますが、
#define疑似命令の強力な機能の1つとして知っておくことは必要です。
前項で見た通り#define疑似命令は非常に強力ですが、
実は、#define疑似命令には更に強力な機能が備わっています。
#define疑似命令で簡単な関数を作ってしまうことが可能です。
#define疑似命令では、名前の後に()で文字を指定すると、
以後の置き換える内容で同じアルファベットの部分を置き換えることが出来ます。
例えば、次の#define疑似命令は、指定されたint型の変数を画面に表示します。
次のプログラムは、先ほどの#define疑似命令を使う例です。#define PRINTM(X) printf("%d\n",X)
このプログラムの実行結果は、次の通りになります。#include <stdio.h> #define PRINTM(X) printf("%d\n",X) int main(void) { int a1 = 100,a2 = 50; PRINTM(a1); PRINTM(a2); return 0; }
ここの#define疑似命令では、名前の後の()の中でXが指定されています。
100
50
この機能や使い方を見る限り、これはまるで関数のようです。
実際、この機能は簡易的な関数の変わりに使われており、マクロと呼ばれています。
マクロの使い方は普通の関数と全く同じですが、仕組みは大きく異なります。
[ マクロ ]
#define疑似命令による置き換えで式などを簡単に表現すること。
しかし、マクロを使う場所全てが置き換わるので、あまり巨大なマクロを作ると、
その為にプログラムのサイズが極端に大きくなることもあります。
その為、一般的には、マクロは、決まり切った数式などに利用されます。
例えば、次のマクロは台形の面積を求めるマクロです。
このプログラムの実行結果は次の通りになります。#include <stdio.h> #define GET_TRAPEZOID_AREA(A,B,H) (A + B) * H / 2 int main(void) { int up,down,h,s; printf("上底、下底、高さ:"); scanf("%d,%d,%d",&up,&down,&h); s = GET_TRAPEZOID_AREA(up,down,h); printf("面積:%d\n",s); return 0; }
この様にすれば、決まり切った数式を何度も入力する必要がなくなります。
上底、下底、高さ:5,10,8
面積:60
#define疑似命令によるマクロは手軽で便利なのですが、
使い方を間違えると思わぬ現象に遭遇することがあります。
例えば、前回の台形の面積を求めるプログラムに置いて、
なんらかの事情で、高さを常に+3しなければならない場合を考えてみます。
次のプログラムは、そのように変更してみた例です。
このプログラムの実行結果は次の通りになります。#include <stdio.h> #define GET_TRAPEZOID_AREA(A,B,H) (A + B) * H / 2 int main(void) { int up,down,h,s; printf("上底、下底、高さ:"); scanf("%d,%d,%d",&up,&down,&h); s = GET_TRAPEZOID_AREA(up,down,h + 3); printf("面積:%d\n",s); return 0; }
高さは+3されているので、結果は前回と同じになるはずなのですが、
上底、下底、高さ:5,10,5
面積:76
これは、#define疑似命令は、単なる置き換え命令でしかないため、
GET_TRAPEZOID_AREA(up,down,h + 3) を (A + B) * H / 2 と置き換えると、
(up + down) * h + 3 / 2 と言う式になってしまいます。
これでは、高さに3が加わるのではなくなってしまい、計算がおかしくなります。
この様に、置き換えで予期しない計算結果になることをマクロの副作用と呼びます。
これを解決する方法は2つあります。1つは、呼び出し時にかっこをつけることです。
と、かっこをつけておけば先に高さに3が加わるので、正常に計算出来ます。GET_TRAPEZOID_AREA(up,down,(h + 3));
もう1つの方法は、マクロの方にかっこをつけておく方法です。
マクロで使われている置き換え部分全てにかっこをつけ、更にマクロ全体にもつけます。
この様にすれば、全ての数値にかっこが付いているので大丈夫です。#define GET_TRAPEZOID_AREA(A,B,H) (((A) + (B)) * (H) / 2)
しかし、気をつけて使用するのは面倒ですし、うっかり忘れてしまうかもしれません。
その為、マクロはあまり多用しない方が良いとされています。
#define疑似命令は定数の宣言にのみ使用して、
数式などの計算には出来る限り関数を使用する方が良いでしょう。