C標準では、コンパイラはビットフィールドを任意のランダムな方法で自由に格納できます。ビットがどこに割り当てられているかを推測することはできません。C標準で指定されていないビットフィールド関連のものをいくつか示します。
不特定の動作
- ビットフィールドを保持するために割り当てられたアドレス指定可能なストレージユニットの配置(6.7.2.1)。
実装定義の動作
- ビットフィールドがストレージユニットの境界にまたがることができるかどうか(6.7.2.1)。
- ユニット内のビットフィールドの割り当ての順序(6.7.2.1)。
ビッグ/リトルエンディアンももちろん実装定義です。これは、構造体が次の方法で割り当てられる可能性があることを意味します(16ビットintを想定)。
PADDING : 8
f1 : 1
f2 : 3
f3 : 4
or
PADDING : 8
f3 : 4
f2 : 3
f1 : 1
or
f1 : 1
f2 : 3
f3 : 4
PADDING : 8
or
f3 : 4
f2 : 3
f1 : 1
PADDING : 8
どちらが当てはまりますか?推測するか、コンパイラの詳細なバックエンドドキュメントを読んでください。これに、ビッグエンディアンまたはリトルエンディアンの32ビット整数の複雑さを追加します。次に、コンパイラがビットフィールド内の任意の数のパディングバイトを追加できるという事実を追加します。これは、構造体として扱われるためです(構造体の最初にパディングを追加することはできませんが、それ以外の場所には追加できません)。
そして、ビットフィールドタイプ=実装定義の動作としてプレーンな「int」を使用した場合、または(符号なし)int =実装定義の動作以外のタイプを使用した場合に、何が起こるかについても触れていません。
したがって、質問に答えるために、ポータブルビットフィールドコードのようなものはありません。C標準はビットフィールドの実装方法について非常にあいまいだからです。ビットフィールドが信頼できる唯一のことは、ブール値のチャンクであり、プログラマーはメモリ内のビットの位置を気にしません。
唯一の移植可能な解決策は、ビットフィールドの代わりにビット単位の演算子を使用することです。生成されるマシンコードはまったく同じですが、決定論的です。ビット単位の演算子は、どのシステムのどのCコンパイラでも100%移植可能です。