ANSI C規格では、ビットフィールドのパック方法の指定が少なすぎて、「コンパイラーはビットフィールドをパックできますが、適切と思われる」よりも優れていますが、それでも多くの場合、コンパイラーは最も効率的な方法で物をパックすることを禁止しています。
特に、構造体にビットフィールドが含まれている場合、コンパイラーは、「通常の」ストレージタイプの1つ以上の匿名フィールドを含む構造体として構造体を格納し、そのような各フィールドを構成するビットフィールド部分に論理的に分割する必要があります。したがって、与えられた:
unsigned char foo1: 3;
unsigned char foo2: 3;
unsigned char foo3: 3;
unsigned char foo4: 3;
unsigned char foo5: 3;
unsigned char foo6: 3;
unsigned char foo7: 3;
場合はunsigned char
8ビットで、コンパイラは、そのタイプの四つのフィールドを割り当て、及び(にされるであろう全てが、1〜2ビットフィールドを割り当てるために必要とされるchar
独自の分野)。すべてのchar
宣言がに置き換えられた場合short
、タイプの2つのフィールドがありshort
、1つは5つのビットフィールドを保持し、もう1つは残りの2つを保持します。
アラインメント制限のないプロセッサunsigned short
では、最初の5つのフィールドに使用unsigned char
し、最後の2つのフィールドに7つの3ビットフィールドを3バイトで格納することにより、データをより効率的にレイアウトできます。3つのバイトに8つの3ビットフィールドを格納することは可能ですが、コンパイラは、「外部フィールド」タイプとして使用できる3バイトの数値タイプが存在する場合にのみ許可できます。
個人的には、ビットフィールドは基本的に役に立たないと定義されていると考えています。コードがバイナリでパックされたデータを処理する必要がある場合は、実際の型の格納場所を明示的に定義し、マクロまたはその他の手段を使用してそのビットにアクセスする必要があります。Cが次のような構文をサポートしていると便利です。
unsigned short f1;
unsigned char f2;
union foo1 = f1:0.3;
union foo2 = f1:3.3;
union foo3 = f1:6.3;
union foo4 = f1:9.3;
union foo5 = f1:12.3;
union foo6 = f2:0.3;
union foo7 = f2:3.3;
このような構文が許可されている場合は、コードがビットサイズを移植可能な方法で使用できるようになります。ワードサイズやバイト順は関係ありません(foo0はf1の最下位3ビットにありますが、これらは下位または上位のアドレス)。ただし、そのような機能がない場合、マクロはおそらくそのようなものを操作する唯一の移植可能な方法です。