最近ビットフィールドと共用体を使用して2byteデータを上位1bitと下位15bitを切り分けるソースコードを見かけました。
ビットフィールドの仕組み自体、忘却の彼方だったので少々調べてみました。
適当ですがこんな感じの定義があったとして。
でunion UUnionValue {
struct SBitAccess {
unsigned int bit0:1;
unsigned int bit1to3:3;
signed int bit4to15:12;
} bitAccess;
unsigned short shortValue;
} unionValue;
に入力ビット列を代入するとunionValue.shortValue
でそれぞれ上位1bitを符号無し、上位2bit〜4bitを符号無し、上位5bit〜16bitを符号有りで取得できると言うもの。unitoValue.bitAccess.bit0
unitoValue.bitAccess.bit1to3
unitoValue.bitAccess.bit4to15
便利ですね。
私は今まで上位2〜4bitを符号無しで取得するには
下位5bit〜16bitを符号付きで取得するには(入力ビット列 >> 12) & 0x0007
のようにしていました。符号付きの方は単純なマスクだけではダメなのが面倒です。ビットフィールドを使用すべきだったのでしょうか?(入力ビット列 & 0x0fff) | ((入力ビット列 & 0x0800) ? 0xf000 : 0x0000)
と思ってすこし調べてみました。
結論
ビット単位の切り分けのためにビットフィールド使っちゃダメ。
ダメな理由は MISRA‐C を読むと何度もしつこく書いてありますが処理系に依存したコードになるからです。
どのあたりが依存しているかというと
- short型の値がどのように格納されるか(ビッグエンディアンorリトルエンディアン)
- ビットフィールドがメモリ上にどのように配置されるか
- ビットフィールドが上位bitから割り当てられるか、下位bitから割り当てられるか
- 1つのビットフィールドが記憶域単位をまたがって配置されるか
記憶域単位というのがbyteを指すのかWORDを指すのかは不明ですが、恐らくbyteかと思います。
本当はC90やC99などの規格を参照すべき所なんですけどね…
web上で検索してみると、処理系依存の部分に触れられていない解説が多いようです。
特にパディングについてはWORDをまたがらないようにパディングされるという説明が多いようですが、規格上はどこでどのようにパディングしようと処理系の自由のようです。
未規定ではなく処理系定義については 処理系でこのような定義 があるはずなので確認すべきなんでしょうねぇ…
今の開発案件の処理系定義って何処にあるんだろ?
0 件のコメント:
コメントを投稿