PRE11-C. マクロ定義をセミコロンで終端しない
ソースコードをより読みやすくするために、マクロがよく使われる。マクロ定義は、単一の文、複数の文、どちらに展開される場合でも、マクロ定義の最後をセミコロンで終端すべきではない。(「PRE10-C. 複数の文からなるマクロは do-while ループで包む」を参照。) セミコロンが必要ならば、マクロ展開後に追加されるべきだ。マクロ定義の末尾についうっかりセミコロンをつけてしまうと、プログラムの制御フローが意図しない形に変化してしまう可能性がある。
この問題を回避するもう1つの方法は、関数形式マクロよりもインライン関数やスタティック関数を使うことである。(「PRE00-C. 関数形式マクロよりもインライン関数やスタティック関数を使う」も参照。)
一般に、マクロ定義の末尾にはセミコロンをつけないようにすべきだ。セミコロンが必要な場合には、マクロを呼び出すコードの側で責任をもってセミコロンをつけるべきである。
違反コード
以下のコード例では、プログラムに for
ループを提供するマクロ定義を行っている。for
ループの本体は、単一の文だけからなる場合でも波括弧で囲んでおくべきだ。(「EXP19-C. if、for、while 文の本体は波括弧で囲む」を参照。) ここで定義するマクロは、ループを実行すべき回数を示す整数引数をとる。プログラマは、マクロ定義の最後にセミコロンをつけてしまっている。
#define FOR_LOOP(n) for(i=0; i<(n); i++); int i; FOR_LOOP(3) { puts("Inside for loop\n"); }
プログラマは次のような出力が得られることを期待している:
Inside for loop Inside for loop Inside for loop
しかし、マクロ定義の最後にセミコロンがあるため、プログラム中の for
ループは空文をもつことになり、"Inside for loop" は一度だけ出力される。つまり、マクロ定義の最後にあるセミコロンによって、プログラムの制御フローが意図したものから変更されてしまっている。
このコード例は、そのまま実際のコードで使われることはないかもしれないが、マクロ定義中のセミコロンが持つ影響を端的に示している。
適合コード
以下の適合コードでは、マクロ定義の末尾にセミコロンはつけていない。セミコロンをつけるかどうかの判断は、そのマクロを使うユーザにゆだねている。
#define FOR_LOOP(n) for(i=0; i<(n); i++) int i; FOR_LOOP(3) { puts("Inside for loop\n"); }
違反コード
以下のコード例では、第一引数 x
の値を1インクリメントし、その結果の値を第二引数 max
の値で剰余するマクロを定義している。
#define INCREMENT(x, max) ((x) = ((x) + 1) % (max)); int index = 0; int value; value = INCREMENT(index, 10) + 2;
プログラマは、index
をインクリメントした結果の値に2を足すことを意図している。しかし残念ながら、実際に得られる値は index
をインクリメントしただけの値に等しくなる。マクロの最後にセミコロンが存在しているからだ。コンパイラは + 2;
を別の文として扱う。コンパイルエラーが出ることはない。コンパイル時に警告オプションを有効にしていなければ、開発の早い段階でマクロ末尾のセミコロンの影響が検出されることはないだろう。
適合コード
以下の適合コードでは、マクロ定義の末尾にセミコロンをつけない。セミコロンをつけるかどうかの判断はマクロを使う者にゆだねている。
#define INCREMENT(x, max) ((x) = ((x) + 1) % (max))
リスク評価
マクロ定義の最後にセミコロンをつけると、プログラムの制御フローが変わり、その結果予期せぬ動作が引き起こされる恐れがある。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
PRE11-C |
中 |
中 |
低 |
P12 |
L1 |
自動検出(最新の情報はこちら)
ツール | バージョン | チェッカー | 説明 |
---|---|---|---|
PRQA QA-C | 8.1 | 3412 | 部分的に実装済み |
関連するガイドライン
CERT C++ Secure Coding Standard | PRE11-CPP. Do not conclude macro definitions with a semicolon |
参考資料
TODO
翻訳元
これは以下のページを翻訳したものです。
PRE11-C. Do not conclude macro definitions with a semicolon (revision 39)