第三十三話 マクロの世界
「では今度はマクロについても、少し教えておくかな」
立花先輩は言った。
「マクロ、ですか? それってエクセルとかにもありますね?」
西原さんが言う。
「ま、定義したとおりにって所は少し似ているけど、Cのマクロはかなり違うわよ」
先輩はメモ帳を開いて、プログラムを書き始める。
「まず、プリプロセッサについて話しておこうかな。実はね、コンパイルの前に行われる前処理があるのよ」
「そうだったんですか」
「うん。特定の設定された文字列を別の文字列に変換するってやつ。頭に#文字がある命令がそうなのよ」
「えっ、それって……いつも行う#includeもそうですね」
「西原さん、鋭いねー。それも実はプリプロセッサ命令なのよ。それから気づいてない? インクルードの最後には、いつも行の最後に必ずつけないといけない『;』セミコロンが無いでしょ? これもプリプロセッサ命令の特徴なの」
「あ、言われてみれば……」
「で、インクルードのほかに、今回紹介するのは、#define命令ね。これはマクロを設定する命令よ。……よし、書き終えた」
先輩が言うので、俺たちは画面を覗き込んだ。
#include <stdio.h>
#define MACRO_NUMBER 10
int main(void)
{
int a = MACRO_NUMBER;
printf("%d", a);
return 0;
}
「これは画面に10を表示するってプログラムね」
「MACRO_NUMBERって全部大文字なんですね」
「それはマクロのお約束ね。別に言語規定で決められてるわけじゃないけど、大半のプログラマは従っているの。そうすると、他の普通の変数とかと区別できて、すぐマクロってわかるからね」
「a = 10って書くのと、どう違うんだろう?」
「うん。いい質問。このa = 10の10みたいに、コードの中に直接数字を書くのは、マジックナンバーって言って、避けるべきプラクティスなのよ。この例だとどっちもあまり変わらないけど、たとえばコード内の100箇所に同じ10の数字があったとして、あとで『実は20でしたー』ってなったと想像してみて」
「うっ。それは、コード内のすべての10を20に修正する羽目になると?」
「うん。そのまま書いてたらね、徹夜で泣く泣く修正作業が待ってるわ。でも、もしマクロを使って、a = MACRO_NUMBERって書いてたら、たとえ100箇所でも1000箇所でも、一行だけMACRO_NUMBER 20って書くだけですべて自動修正されるでしょ?」
「あ、そうか! それでマクロってあるんだ」
俺は納得した。
「ふふっ。じつは定数使うほかの方法もあるんだけど、マクロを使うのがCでは一般的ね。これがマクロの使い方、第一段」
「他にもあるんですか?」と西原さん。
「うん。第二段として、マクロで関数っぽいのを作ることも出来るのよ」
「なぬっ」
「たとえば、max関数をマクロにしたら、こうなるかなー」
#define MAX(a,b) ((a)>(b)?(a):(b))
「カッコが多いな」
「Lispっぽくなるの」とサヤちゃん。
「これは、マクロ展開後に、算術優先順位の関係で、答えがおかしくなることがあるから、値を保護するために、カッコで優先順位を最高位に引き上げているのね」
「うーむ」
「あと、まだ説明してなかったけど、右側の a ? b : c って式は、三項演算子って言って、If文に似ているの。もしaの式がTrueを返すなら、bを、Falseを返すならcの中の式を実行するの」
「ふむ。だと、これだと、aがbより上なら、aを、下ならbを戻り値に返すってことかな?」
「そう。引数aとbのどちらが大きいかを比べる関数マクロね」
「関数とマクロを使うのは、どう違うんだろう」
「一つは、早さね。マクロだと、そのままコード上に中身が展開されるから、関数を呼び出したり返したりする手間が省ける分、速度が上がるの。もっとも、いちいちコード上にマクロは展開されるから、実行ファイルがその分大きくなる欠点もあるけど」
「なるほど」
「ただ、マクロには特有の問題もあるから注意してね。たとえば、こういうのとか」
int a = 10
int result = MAX(++a , 10);
「これだと、中の++aが、2回、実行されちゃうのよ」
「え? なんで?」
「マクロを二つの引数で置き換えると、こうなるよね。 result = ((++a)>(10)?(++a):(10)); ++は前に置いているから、1つ足してから戻り値が帰るから11になる。10より上だから、一番目の(++a)が選択されて、また++aが実行されて、12になるの」
「うわっ。なんという」
「これがa = 9だったら、後ろの方が選ばれるから1回のみでしょうね。マクロ特有の問題って、こういう事」
「どうすればいいんでしょう」と西原さんも心配そう。
「一番の簡単な解決法は、マクロ内では値を変えるような式を入れない! ややこしい事をしなければ、ややこしい結果にはならないの」
そりゃ、そうだ。
「こういう問題点も理解した上で使うならば、マクロはとても便利よ。大規模なプログラムになると、制御にマクロを使っているのが多いから、コードを読んでみるといろいろ参考になるわよ」
そういうと、先輩は話を終えた。