PRE01-C. マクロ内の引数名は括弧で囲む
マクロ定義におけるすべての引数名は括弧で囲むこと。「PRE00-C. 関数形式マクロよりもインライン関数やスタティック関数を使う」と「PRE02-C. マクロ置換リストは括弧で囲む」も参照。
違反コード
以下の CUBE() マクロ定義は、引数名を括弧で囲んでいない。
#define CUBE(I) (I * I * I)
そのため、次のような呼び出し
int a = 81 / CUBE(2 + 1);
は次のように展開される。
int a = 81 / (2 + 1 * 2 + 1 * 2 + 1); /* 11 に評価される */
これは明らかに、求めようとした結果ではない。
適合コード
CUBE() マクロのすべての引数名を括弧で囲むことで、次のように呼び出されるときに正しく展開されるようになる。
#define CUBE(I) ( (I) * (I) * (I) ) int a = 81 / CUBE(2 + 1);
例外
PRE01-C-EX1: 置き換えられるテキスト中で引数名がコンマで囲まれている場合、実引数がいかに複雑であっても、マクロの引数に括弧をいれる必要はない。コンマは他のあらゆる演算子よりも優先順位が低いため、実引数が予期せぬ方法で解析されることはない。関数呼び出し時に引数を区切るコンマ区切りは、他の演算子よりも優先順位は低いが、厳密にはコンマ演算子とは異なるものである。
#define FOO(a, b, c) bar(a, b, c) /* ... */ FOO(arg1, arg2, arg3);
PRE01-C-EX2: マクロ引数を個別に括弧で囲むことができない場合として、## 演算子を用いて字句(token)を連結する場合、# 演算子を用いてマクロ引数を文字列に変換する場合、隣り合う文字列リテラルを連結する場合などがある。以下に示す JOIN() マクロは 2 つの引数を連結して新しい字句を生成する。SHOW() マクロでは、その引数を文字列リテラルに変換し、さらに隣接する文字列と連結した形で printf() の第1引数とし、同時に %d に対応する printf() の第2引数としても展開している。たとえば、SHOW(66); というコードは printf("66" " = %d\n", 66); に展開される。
#define JOIN(a, b) (a ## b) #define SHOW(a) printf(#a " = %d\n", a)
## 演算子を用いた字句の連結に関する詳細は、「PRE05-C. 字句の結合や文字列化を行う際のマクロ置換動作をよく理解する」を参照のこと。
リスク評価
マクロ中の引数名を括弧で囲まないと、予期せぬプログラムの動作を引き起こす可能性がある。
|
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
|---|---|---|---|---|---|
|
PRE01-C |
中 |
中 |
低 |
P12 |
L1 |
自動検出(最新の情報はこちら)
| ツール | バージョン | チェッカー | 説明 |
|---|---|---|---|
| ECLAIR | 1.2 | CC2.PRE01 | 実装済み |
| 9.5.6 |
78 S |
Enhanced Enforcement |
|
| Parasoft C/C++test | 9.5 | MISRA2004-19_10 | Fully implemented |
| PRQA QA-C | 8.2 | 3410 | 実装済み |
関連するガイドライン
| SEI CERT C++ Coding Standard | PRE01-CPP. Use parentheses within macros around parameter names |
| ISO/IEC TR 24772:2013 | Operator Precedence/Order of Evaluation [JCW] Pre-processor Directives [NMP] |
| MISRA C:2012 |
Rule 20.7 (required) |
参考資料
| [Plum 1985] | |
| [Summit 2005] | Question 10.1 |
翻訳元
これは以下のページを翻訳したものです。
PRE01-C. Use parentheses within macros around parameter names (revision 149)



