サーチ…
前書き
ビットフィールドは、CおよびC ++構造体をしっかりとパックしてサイズを縮小します。これは苦労しないように見えます。メンバーのビット数を指定し、コンパイラはビットを混同します。この制限は、ビットフィールドメンバのアドレスを取ることができないことである。これは、ビットフィールドメンバが混在して格納されているからである。 sizeof()
も禁止されています。
ビットフィールドのコストは、メンバー値を抽出または変更するためにメモリを取得し、ビット単位の操作を適用する必要があるため、アクセスが遅くなります。これらの操作は、実行可能なサイズにも追加されます。
備考
ビット演算はどれくらいの費用がかかりますか?単純な非ビットフィールド構造を仮定します。
struct foo {
unsigned x;
unsigned y;
}
static struct foo my_var;
後のコードでは、
my_var.y = 5;
sizeof (unsigned) == 4
場合、xは構造体の先頭に格納され、yは4バイトに格納されます。生成されるアセンブリコードは次のようになります。
loada register1,#myvar ; get the address of the structure
storei register1[4],#0x05 ; put the value '5' at offset 4, e.g., set y=5
これは、xがyと混同されていないため、簡単です。しかし、ビットフィールドを使って構造体を再定義すると想像してください:
struct foo {
unsigned x : 4; /* Range 0-0x0f, or 0 through 15 */
unsigned y : 4;
}
x
とy
両方に4ビットが割り当てられ、1バイトを共有します。したがって、構造体は8ではなく1バイトを占有しますy
上限に設定したと仮定してアセンブリをy
と設定します。
loada register1,#myvar ; get the address of the structure
loadb register2,register1[0] ; get the byte from memory
andb register2,#0x0f ; zero out y in the byte, leaving x alone
orb register2,#0x50 ; put the 5 into the 'y' portion of the byte
stb register1[0],register2 ; put the modified byte back into memory
これらの構造が数千ないし数百万ある場合、これは良いトレードオフになる可能性があり、キャッシュにメモリを保持したり、スワッピングを防止したり、実行可能ファイルを膨らませてこれらの問題を悪化させたり、すべてのことと同様に、良い判断をしてください。
デバイスドライバの使用:デバイスドライバの賢明な実装方法としてビットフィールドを使用しないでください。ビットフィールドの格納レイアウトはコンパイラ間で必ずしも一貫しているわけではなく、そのような実装は移植性がありません。設定値へのリード・モディファイ・ライトは、予期しない動作を引き起こすデバイスが予期しない動作をする可能性があります。
宣言と使用法
struct FileAttributes
{
unsigned int ReadOnly: 1;
unsigned int Hidden: 1;
};
ここでは、これらの2つのフィールドのそれぞれが1ビットのメモリを占有します。これは、変数名の後に: 1
式で指定されます。ビットフィールドの基本型は任意の整数型(8ビットintから64ビットint)です。 unsigned
型を使用することをお勧めします。そうでないと驚きが生じることがあります。
より多くのビットが必要な場合は、「1」を必要なビット数に置き換えます。例えば:
struct Date
{
unsigned int Year : 13; // 2^13 = 8192, enough for "year" representation for long time
unsigned int Month: 4; // 2^4 = 16, enough to represent 1-12 month values.
unsigned int Day: 5; // 32
};
全体の構造体はわずか22ビットを使用しており、通常のコンパイラ設定では、この構造体のsizeof
は4バイトになります。
使い方はとてもシンプルです。変数を宣言し、通常の構造のように使用してください。
Date d;
d.Year = 2016;
d.Month = 7;
d.Day = 22;
std::cout << "Year:" << d.Year << std::endl <<
"Month:" << d.Month << std::endl <<
"Day:" << d.Day << std::endl;