トリッキーコードネット トップへ戻る   C/C++, Java, Perl, PHP, JavaScript, アルゴリズム, ショートコーディング, IOCCCコードの解説, 等々

サイト情報

トリッキーなコード

7行プログラミング

物凄いコード集

アルゴリズム

データ構造

C/C++な話題

コードサンプル

ツール/環境構築

開発ノウハウ 等

ネタ/ジョーク集

おススメ書籍/サイト

サイトTOP >> C/C++な話題 >> バグの温床となりえるマクロについて

バグの温床となりえるマクロについて (C言語)

C言語でマクロを使用する際の注意点(気をつけないと予期せぬバグ発生の原因となりえる)について書きます ^^;)


まずは、以下のコードを見てください。
 1 : #include <stdio.h>
 2 :
 3 : #define CUBE(NUM) (NUM * NUM * NUM)
 4 :
 5 : int main(void)
 6 : {
 7 :     int num = 4;
 8 :
 9 :     printf("%d の三乗は %d\n", num, CUBE(num));
10 :
11 :     return 0;
12 : }
結果) バグのあるマクロ例 3行目で定義しているCUBEマクロは、その名の示すとおり三乗を求めるマクロです。 一見正常に動作している様に見えますが、このマクロ、実はバグの温床になっています。 以下のコードを見てください。(※ 冒頭のコードの一部を修正したものです)
 1 : #include <stdio.h>
 2 :
 3 : #define CUBE(NUM) (NUM * NUM * NUM)
 4 :
 5 : int main(void)
 6 : {
 7 :     printf("%d の三乗は %d\n", 10 + 20, CUBE(10 + 20) );
 8 :
 9 :     return 0;
10 : }
結果) マクロがバグを引き起こした例 30の三乗という事で、 30 x 30 x 30 = 27000 が表示されるかと思いきや、430が表示されてしまいました。 この理由は、CUBEマクロを展開してみれば直ぐに分かります。 CUBE(10 + 20) ⇒ (10 + 20 * 10 + 20 * 10 + 20) ⇒ (10 + 200 + 200 + 20) ⇒ 430 演算子には優先順位が有る為、 この様に 「値を計算するマクロ中に、数値と演算子のセットを入れると、予期せぬバグを引き起こす」 可能性があります。 これを防止する為には、「マクロへ演算子を渡さない」という鉄の掟を作るか(← 笑)、以下の様にマクロを修正します。
#define CUBE(NUM) ((NUM) * (NUM) * (NUM))
つまり、マクロに渡された値を、括弧で囲むという事です。
 1 : #include <stdio.h>
 2 :
 3 : #define CUBE(NUM) ((NUM) * (NUM) * (NUM))
 4 :
 5 : int main(void)
 6 : {
 7 :     printf("%d の三乗は %d\n", 10 + 20, CUBE(10 + 20) );
 8 :
 9 :     return 0;
10 : }
結果) マクロのバグを修正した例 はい、一件落着~~♪ ・・・と思いきや、実はこの、値を括弧で囲ったマクロでも、バグの温床になっています。
 1 : #include <stdio.h>
 2 :
 3 : #define CUBE(NUM) ((NUM) * (NUM) * (NUM))
 4 :
 5 : int main(void)
 6 : {
 7 :     int i = 2;
 8 :
 9 :     printf("%d の三乗は %d\n", i, CUBE(++i) );
10 :
11 :     return 0;
12 : }
結果) マクロがバグを引き起こした例2 9行目のコードを展開すると、以下の様になります。
printf("%d の三乗は %d\n", i, ((++i) * (++i) * (++i)) );
副作用完了点までの評価順序は未定義の為、この場合の結果は保証されません。 つまり、処理系によって結果が異なる可能性があるという事です orz では、この場合にどうすれば良いのかというと、(マクロからは遠ざかってしまいますが)インライン関数を使用します。
 1 : #include <stdio.h>
 2 :
 3 : inline int cube(int num)
 4 : {
 5 :     return num * num * num;
 6 : }
 7 :
 8 : int main(void)
 9 : {
10 :     int i = 2;
11 :
12 :     printf("%d の三乗は %d\n", i, cube(++i) );
13 :
14 :     return 0;
15 : }
結果) マクロをインライン関数に置き換えた例 とりあえず今回はここまで♪
         このエントリーをはてなブックマークに追加   


作業効率化・ライフハックのオススメ記事




コンピュータ・テクノロジーのオススメ記事





恋愛・人間関係のオススメ記事




※ 当サイトは、トップページからリンクで辿る事の出来るページに限り、リンクフリーです。
※ 当サイトの閲覧/利用によって生じた如何なる損害も、当サイト管理人は責任を負いません。
※ 当サイトの内容を転載される場合は、当サイトへのリンクをお願い致します。