ビットフィールドのためのポータブルなコード
ビットフィールドは、構造体のサイズをコンパクトにするために便利な仕組みだ。
typedef struct { int bar: 24; int baz: 8; } Foo;
32 ビット環境なら、こんな構造体だと、この構造体は 4 バイトですむ。
ただ、24 ビットとか 8 ビットというような環境に依存するコードをハードコーディングしたくない。
ここでは、baz が 8 ビット、bar はその残り、という要求仕様がある場合で検討してみる。要するに 8 はハードコードでも良いということにする。
typedef struct { int bar: sizeof(int) - 8; int baz: 8; } Foo;
まず思いつくのはこんな感じのコードだけど、ビットフィールドに sizeof 演算子は使用できないのでコンパイルエラーが発生する。ビットフィールドに sizeof 演算子が使用できないのは ANSI の仕様だ。
ということで、ポータブルなビットフィールドを書くのは以下のようにしなければならない。
#include <stdio.h> #include <limits.h> #if UINT_MAX==(1<<32)-1 #define INT_BIT 32 #elif UINT_MAX==(1<<64)-1 #define INT_BIT 64 #else #error "This product does not support this platform." #endif typedef struct { int bar: INT_BIT - 8; int baz: 8; } Foo; int main(int argc, char *argv[]) { printf("%d\n", sizeof(Foo)); return 0; }
ANSI では limits.h に CHAR_BIT という char のビット数が定義されてはいるけど、INT_BIT のようなものは定義されていないため、UINT_MAX から類推するしかない。ただ、unsigned int が 32 バイトなのに、UINT_MAX が (1<<32)-1 ではない(与えられたビットを全部使用しない)変態的な処理系も存在するかも知れないので注意が必要だ。