INT09-C. 列挙定数が一意の値に対応することを保証する
C言語の列挙型は、列挙定数として知られる識別子、つまり列挙子によって表される有限個の値からなる型を定義する。列挙子は、値を int
として表現可能な整数定数式である。言語仕様では、同じ型の複数の列挙子が同じ値を持ってもよいとされているが、一般には、同じ型に属する各列挙子は互いに異なる値を持つことが期待されるだろう。同じ型に属する複数の列挙子が同じ値を持つように定義すると、自明でないエラーにつながる可能性がある。
違反コード
以下のコード例では、Color
型の 2 つの列挙子の値が明示的に定義されている。プログラマには自明ではないかもしれないが、yellow
と indigo
の値は 6 となり、green
と violet
の値は 7 となる。このような定義から生じる最も危険性の低いエラーは、これらの列挙子を switch
文のラベルとして使うことだろう。switch
文のラベルは互いに異なる値であることが要求されるため、次のようなコードを規格合致処理系でコンパイルすると診断メッセージが出力されることになる。
enum Color { red=4, orange, yellow, green, blue, indigo=6, violet };
const char* color_name(enum Color col) {
switch (col) {
case red: return "red";
case orange: return "orange";
case yellow: return "yellow";
case green: return "green";
case blue: return "blue";
case indigo: return "indigo"; /* Error: duplicate label (yellow) */
case violet: return "violet"; /* Error: duplicate label (green) */
}
}
適合コード
違反コード例で説明したエラーを防ぐためには、列挙型宣言を次の形式のいずれかにする必要がある。
- 明示的な整数の代入をしない:
enum Color { red, orange, yellow, green, blue, indigo, violet };
- 最初のメンバのみに値を代入する(残りのメンバの値はシーケンシャルになる):
enum Color { red=4, orange, yellow, green, blue, indigo, violet };
- すべてのメンバに値を代入して値の関係を明確にする:
enum Color {
red=4,
orange=5,
yellow=6,
green=7,
blue=8,
indigo=6,
violet=7
};
また、将来コードをメンテナンスする人がこれを間違いだと誤解しないように、なぜ複数の列挙型メンバに同じ値を代入しているのかを説明するコメントをつけておくのがオススメだ。
最初の列挙子がゼロ以外の値である必要がなければ、3つのオプションのうち最初の「明示的な整数の代入をしない」が最もシンプルで好ましい方法である。
例外
INT09-EX1: 同じ値の列挙子を2つ以上持つ列挙型を定義したい場合は、重複する値を持たせたい列挙子の値を、元の列挙子を使って定義すべきである。これにより、同じ値にしたいという意図を、コードを読む人にもコード分析ツールにも明確に伝えることができる。ただし、このように定義された列挙子は、一意の値が必要なコンテキスト (前述の switch
文など) では使えない点に注意。
enum Color { red, orange, yellow, green, blue, indigo, violet=indigo };
リスク評価
列挙型の各メンバが一意の値を持つことを保証しておかないと、予期せぬ結果を招くおそれがある。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
INT09-C |
低 |
中 |
中 |
P4 |
L3 |
自動検出
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
CodeSonar | 4.0 | LANG.STRUCT.ENUMINIT | Inconsistent Enumerator Initialization |
|
|
|
|
ECLAIR |
1.2 |
CC2.INT09 |
実装済み |
LDRA tool suite |
8.5.4 |
85 S |
実装済み |
PRQA QA-C | v8.2 |
0724 |
実装済み |
関連するガイドライン
CERT C++ Coding Standard | INT09-CPP. Ensure enumeration constants map to unique values |
CERT Oracle Secure Coding Standard for Java | 28. Do not attach significance to the ordinal associated with an enum |
ISO/IEC TR 24772:2013 | Enumerator Issues [CCB] |
MISRA C:2012 | Rule 8.12 (required) |
翻訳元
これは以下のページを翻訳したものです。
INT09-C. Ensure enumeration constants map to unique values (revision 70)