INT12-C. 式中で使用される単なるintのビットフィールドの型について勝手な想定をしない
ビットフィールドを使用することで、フラグ値やごく狭い範囲の値しか取らない整数値をひとまとめにしてメモリ領域を節約することができる。
ビットフィールドについて、型 int
が signed int
と同じ型を意味するか、あるいは unsigned int
と同じ型を意味するかは処理系定義である。また、C標準 [ISO/IEC 9899:2011] では、整数拡張について次のように記載されている: 「元の型のすべての値を int
で表現可能な場合(ビットフィールドの場合とりうる値の範囲はビット幅によって決まる)、int
型に変換する。そうでない場合、unsigned int
型に変換する。」
この問題は「INT07-C. 数値には符号の有無を明示した文字型のみを使用する」で議論した「単なる」 char
の符号にまつわる問題に類似している。符号無しとして扱われる「単なる」 int
型ビットフィールドは、フィールド幅が int
よりも小さい限り、int
型に拡張される。なぜなら int
型で元の型のすべての値を保持できるからである。これは「単なる」 char
が符号無しとして扱われるのと同じ動作である。しかし、符号無しとして扱われる「単なる」 int
型ビットフィールドは、フィールド幅が int
と等しい場合、unsigned int
に拡張される。この違いゆえに、「単なる」 int
型ビットフィールドは「単なる」 char
よりもやっかいなのである。
_Bool
、int
、signed int
、unsigned int
以外のビットフィールドは処理系定義である。これらは、指定されたフィールド幅が少なくとも CHAR_BIT*sizeof(int)
と同じ幅であれば、上に引用した整数拡張に従う。しかし、より広いフィールド幅は移植性が低い。
違反コード
以下のコードは処理系定義の動作に依存している。「単なる」 int
型ビットフィールドが符号付きか符号無しかにより、-1
か 255
のいずれかを出力する。
struct { int a: 8; } bits = {255}; int main(void) { printf("bits.a = %d.\n", bits.a); return 0; }
適合コード
以下の適合コードでは、unsigned int
型ビットフィールドを使っており、処理系定義の動作に依存していない。
struct { unsigned int a: 8; } bits = {255}; int main(void) { printf("bits.a = %d.\n", bits.a); return 0; }
リスク評価
ビットフィールドの型やレイアウトについて勝手な思い込みをすると、予期せぬプログラムの欠陥につながるおそれがある。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
INT12-C |
低 |
低 |
中 |
P2 |
L3 |
自動検出
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Compass/ROSE |
|
|
|
ECLAIR |
1.1 |
bitftype |
実装済み |
LDRA tool suite |
V. 8.5.4 |
73 S |
実装済み |
PRQA QA-C | 8.1 | 0634 (I) | 実装済み |
関連するガイドライン
CERT C++ Secure Coding Standard | INT12-CPP. Do not make assumptions about the type of a plain int bit-field when used in an expression |
ISO/IEC TR 24772:2013 | Bit Representations [STR] |
MISRA-C | Rule 12.7 |
参考資料
[ISO/IEC 9899:2011] | Section 6.3.1.1, "Boolean, Characters, and Integers" |
翻訳元
これは以下のページを翻訳したものです。
INT12-C. Do not make assumptions about the type of a plain int bit-field when used in an expression (revision 76)