C 言語 マクロ講座 邪道編2007年03月24日 11時26分25秒

マクロは、プリプロセッサで展開されてしまう。そのため、安易に return を、マクロ関数内で使うと期待しない動作に遭遇する事もある。そのため、マクロ関数内で return を使ってはいけないという方針を作る所もある。

例では、SET という関数を定義した。今回の例は見ても、有用性はあまり良く見えてこないかもしれない。


% cat set.c              
#ifndef LIB
  #include 
#endif

#define SET(a, boolean) { if(boolean) return 0; a = __LINE__;}

int main()
{
    int a = 0;

    SET(a, 0);
    printf("a = %d\n", a);

    SET(a, 1);
    printf("a = %d\n", a);
}

例えば、外部データを内部形式に変換する時を考える。外部データには何が含まれているか分からないし、正しい値の範囲に収まっているとも限らない。そこで、一つずつ検証しながら、内部形式に変換していくことになる。

大型の構造体を変換するときには、検査結果が正しければ次に進み、悪ければ処理を止める。 もし、同一の事をマクロを使わなければ、こうなるだろう。


% cat set2.c 
#ifndef LIB
  #include 
#endif

int main()
{
    int a = 0;

    if(0)
        a = __LINE__;
    else
        return;
    printf("a = %d\n", a);

    if(1)
        a = __LINE__;
    else
        return;
    printf("a = %d\n", a);
}

いちいち全ての場合に if-else return を書き連ねる事になる。この例では二つしかないのでまんざらでもないが、もし何十個もこんなものが並んでいるのを見つけたら、気が滅入ってしまうだろう。

return を実行するマクロ関数は邪道と言われる事も多いが、時と場合によってはとても重宝する。

実行結果とプリプロセッサを通した結果だ。


% make set
cc -O2 -fno-strict-aliasing -pipe   set.c  -o set
% ./set 
a = 11
% gcc -E -DLIB set.c 
# 1 "set.c"
# 1 ""
# 1 ""
# 1 "set.c"






int main()
{
    int a = 0;

    { if(0) return 0; a = 11;};
    printf("a = %d\n", a);

    { if(1) return 0; a = 14;};
    printf("a = %d\n", a);
}

前回次回