C++ 構造体の構文「a :」とは何ですか?b」の意味
-
05-07-2019 - |
質問
C++ 構造体がある場合、次のような 64 ビット データ ワードを定義します。
struct SMyDataWord
{
int Name : 40;
int Colour : 24;
};
は何ですか : 40
構文の意味...最初の 40 ビットは名前用に予約され、残りの 24 ビットは色用に予約されているという意味ですか?
このように使われているようですが、私はこれまで見たことがありません。
解決
ビットフィールド。 Name
は40ビット幅、 Colour
は24ビット幅です。したがって、構造体には少なくとも64ビットがあります。私のシステムでは、64ビットは8バイトになります。
他のヒント
これはビットフィールドの定義です。
Nameは、正確に40ビットの情報を保存できる整数です。カラーは24ビットを保存できます。
これは、頻繁に必要な構造のスペースを節約したり、CPUで処理しやすいサイズにコードを圧縮したりするためによく行われます(64ビットマシンの場合、Fitは正確に64ビットマシンのCPUレジスタに収まります)。
ビットフィールドにアクセスするコードの実行速度は少し遅くなります。
ほとんどすべてのことを覚えておいてください ビットフィールドは実装です 依存。たとえば、ビット 左から右に保存されるか、 右から左は実際の ハードウェアアーキテクチャ。さらに、 各コンパイラは異なるメンバーを使用します 整列モデル、これがサイズの理由です 最適化されたBillingRecの12 9ではなくバイト。 ビットフィールドのアドレスも作成できません ビットの配列。最後に、ほとんどの ビットフィールドの使用の実装 速度のオーバーヘッドが発生します。したがって、 コードを最適化し、測定する 特定の最適化の効果と 使用する前のトレードオフ それ。
ここ sizeof
内部で何が起こっているかをうまく示しています。
#include <iostream>
#include <climits>
struct bc_1 {
int a : 1;
int b : 1;
};
struct bc_2 {
int a : 31;
int b : 1;
};
struct bc_3 {
int a : 32;
int b : 1;
};
struct bc_4 {
int a : 31;
int b : 2;
};
struct bc_5 {
int a : 32;
int b : 32;
};
struct bc_6 {
int a : 40;
int b : 32;
};
struct bc_7 {
int a : 63;
int b : 1;
};
int main(int argc, char * argv[]) {
std::cout << "CHAR_BIT = " << CHAR_BIT;
std::cout << " => sizeof(int) = " << sizeof(int) << std::endl;
std::cout << "1, 1: " << sizeof(struct bc_1) << std::endl;
std::cout << "31, 1: " << sizeof(struct bc_2) << std::endl;
std::cout << "32, 1: " << sizeof(struct bc_3) << std::endl;
std::cout << "31, 2: " << sizeof(struct bc_4) << std::endl;
std::cout << "32, 32: " << sizeof(struct bc_5) << std::endl;
std::cout << "40, 32: " << sizeof(struct bc_6) << std::endl;
std::cout << "63, 1: " << sizeof(struct bc_7) << std::endl;
}
以下の内容は、コンパイラと OS、場合によってはハードウェアによって異なります。gcc-7 を使用した macOS 上 ( CHAR_BIT
= 8、32 ビット int
(すなわち、64ビットの半分 long
) もっている sizeof(int)
= 4) これは私が見た出力です:
CHAR_BIT = 8 => sizeof(int) = 4
1, 1: 4
31, 1: 4
32, 1: 8
31, 2: 8
32, 32: 8
40, 32: 12
63, 1: 8
これにより、いくつかのことがわかります。両方のフィールドの場合、 int
単一に収まるタイプ int
(すなわち、上の例では 32 ビット)、コンパイラは 1 つのみを割り当てます。 int
の記憶量 (bc_1
そして bc_2
)。一度、シングル int
ビットフィールドを保持できなくなったので、2 番目のビットフィールドを追加します (bc_3
そして bc_4
)。ご了承ください bc_5
定員に達しています。
興味深いことに、許可されているよりも多くのビットを「選択」できます。見る bc_6
. 。ここで g++-7 は警告を出します。
bitfields.cpp::30:13: warning: width of 'bc_6::a' exceeds its type
int a : 40;
^~
ご了承ください:これについては、clang++ で詳しく説明しています。
bitfields.cpp:30:9: warning: width of bit-field 'a' (40 bits) exceeds the width of its type; value will be truncated to 32 bits [-Wbitfield-width]
int a : 40;
^
ただし、内部ではコンパイラが別の割り当てを行っているようです。 int
の価値のある思い出。少なくとも、正しいサイズが決定されます。コンパイラがこのメモリにアクセスしないよう警告しているのだと思います。 int a = bc_6::a
(私はそう賭けます int a
この場合、フィールドの最初の 32 ビットのみが含まれます。 bc_6::a
...)。これは次によって確認されています bc_7
合計の大きさは2つです int
s ですが、最初のフィールドでほとんどがカバーされます。
ついに交換 int
と long
上記の例では、期待どおりに動作します。
CHAR_BIT = 8 => sizeof(long) = 8
1, 1: 8
31, 1: 8
32, 1: 8
31, 2: 8
32, 32: 8
40, 32: 16
63, 1: 8