
この記事はかなり昔に執筆されており、誤りを含む場合があります。
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 : }9行目のコードを展開すると、以下の様になります。
副作用完了点までの評価順序は未定義の為、この場合の結果は保証されません。 つまり、処理系によって結果が異なる可能性があるという事です orz では、この場合にどうすれば良いのかというと、(マクロからは遠ざかってしまいますが)インライン関数を使用します。printf("%d の三乗は %d\n", i, ((++i) * (++i) * (++i)) );結果)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 : }・・・まぁ、インライン関数って 開発環境によっては使用できなかったりするんですがね^^;) とりあえず今回はここまで♪

30の三乗という事で、 30 x 30 x 30 = 27000 が表示されるかと思いきや、430が表示されてしまいました。
この理由は、CUBEマクロを展開してみれば直ぐに分かります。
CUBE(10 + 20) ⇒ (10 + 20 * 10 + 20 * 10 + 20) ⇒ (10 + 200 + 200 + 20) ⇒ 430
演算子には優先順位が有る為、
このように
「値を計算するマクロ中に、数値と演算子のセットを入れると、予期せぬバグを引き起こす」
可能性があります。
これを防止する為には、「マクロへ演算子を渡さない」という鉄の掟を作るか(← 笑)、以下の様にマクロを修正します。
はい、一件落着~~♪
・・・と思いきや、実はこの、値を括弧で囲ったマクロでも、バグの温床になっています。
9行目のコードを展開すると、以下の様になります。
・・・まぁ、インライン関数って 開発環境によっては使用できなかったりするんですがね^^;)
とりあえず今回はここまで♪