2013年8月31日土曜日

マクロとインライン関数

突然ですが、引数つきマクロはインライン関数のように定義内容をコード上に展開する
機能を持っています。そのため、引数つきマクロを使うと、インライン関数と同じことが
できます。しかし、できるだけインライン関数を使ったほうがよいということがあります。

引数つきマクロを使って、2つの数から大きいほうの数値を求めるマクロを例に
見て行きましょう。^^

//3項演算子を使っていると、とってもできる人みたいに見える気がします。
#define MAXNUM(a, b)    ( (a) > (b) ? (a) : (b) )

ちなみに同じ処理をインライン関数にすると、次のようになります。

inline int MaxNumFunc(int a, int b)
{
    if (a > b) return a;

    return b;
}

引数つきマクロはわずか1行ですが、インライン関数は空行も含めると6行にも
なってしまいました。
一見すると引数つきマクロのほうが便利そうなのですが、実は副作用がでる
ケースも存在します。
例えば次のように実行すると、引数つきマクロではインクリメントが2回行われて
しまうのです。
b1++が2ヶ所に展開されるので、b1が2回インクリメントされてしまいます。(^_^;)

    :
int a1 = 11, b1 = 13;
//呼び出しで1回、マクロ内の判定で1回で合計2回b1がインクリメントされます。
int n1 = MAXNUM(a1++, b1++);
cout << "a1 = " << a1 << " b1 = " << b1 << endl;
cout << "n1 = " << n1 << endl;

int a2 = 12, b2 = 14;
//インライン関数では、インクリメントが1回です。
int n1 = MaxNumFunc(a2++, b2++);
cout << "a2 = " << a2 << " b2 = " << b2 << endl;
cout << "n2 = " << n2 << endl;
    :

実行結果
# ./test
a1 = 12 b1 = 15
n1 = 14
a2 = 13 b2 = 15
n2 = 14

どうやら違う結果になりえるというのが理解いただけたかと。(^_^;)
また、モノによって使えるマクロ、使えないマクロを判断するのは面倒ですから
それだったらはじめからインライン関数で作っておけば、今回のようなケースでも
対応可能となり問題は発生しません。
ひょっとしたらバグっているけども気づかれないパターンで救われているのかしら?
マクロになっているところは一度見直してみるのもいいかもしれませんね。

約束の時間計測でインライン関数の高速ぶりを検証
前回はインライン関数の高速ぶりが全く伝わらなかったのでリベンジしようかと。
ということで、sqrt(x * x + y * y) の計算を普通の関数およびインライン関数で
1000000 回計算するというサンプルを見つけたのでコレを試してみます。(^^)
http://www.sist.ac.jp/~suganuma/learn/2-bu/7-sho/7-5/7-5.htm

実行結果のみ載せています。
# ./functiontest
answer is 11
time = 0.522189

# ./inlinetest
answer is 11
time = 0.505161

これは、インライン関数のほうが0.017028秒早いですね。
サンプルでは微々たる差分ですが、この積み重ねでユーザーがイライラしない
システムというのが出来上がります。
プロになることを見据えて、実行時間にも拘りたいものですね。(^^)


今日の名言
あの太陽の輝く遥か彼方に、私の最も憧れている何物かがあります。たとえ、そこに
達することができなくても、私は頭を上げてその美しさを眺め、そこにあることを信じ、
その指差す方向へついていくことが出来るのです。
                                 ルイーザ・メイ・オルコット

心を打ち込んで事に当たれば、右手を二本得たも同然である。
                              エルバート・ハバード

熱中ほど伝染しやすいものはない。これこそ真のオルフェウス神話である。熱中は
岩をも動かし野獣をもうっとりさせる。それは誠意の守護神であり、これなくして
勝利はありえない。
                                 エドワード・ブルワー・リットン