ビットフィールドでテストを行ったところですが、その結果は驚くべきものです。
class test1 {
public:
bool test_a:1;
bool test_b:1;
bool test_c:1;
bool test_d:1;
bool test_e:1;
bool test_f:1;
bool test_g:1;
bool test_h:1;
};
class test2 {
public:
int test_a:1;
int test_b:1;
int test_c:1;
int test_d:1;
int test_e:1;
int test_f:1;
int test_g:1;
int test_h:1;
};
class test3 {
public:
int test_a:1;
bool test_b:1;
int test_c:1;
bool test_d:1;
int test_e:1;
bool test_f:1;
int test_g:1;
bool test_h:1;
};
結果は次のとおりです。-
sizeof(test1) = 1 // This is what I'd expect. 8 bits in a byte
sizeof(test2) = 4 // Reasonable. Maybe padded out to the size of an int.
sizeof(test3) = 16 // What???
これはあなたが期待するものですか、それともコンパイラのバグですか? (Codegear C++ Builder 2007、ところで...)
コンパイラは、test3のすべてのメンバーを整数サイズの境界に配置しました。ブロックが特定のタイプ(整数ビットフィールドまたはブールビットフィールド)に使用されると、コンパイラは次の境界まで別のタイプのビットフィールドを割り当てません。
バグだとは思えません。それはおそらくあなたのシステムの基礎となるアーキテクチャと関係があります。
編集:
c ++コンパイラは、次のようにメモリ内のビットフィールドを割り当てます。いくつかの連続するビットフィールドメンバー 同じタイプの 順番に割り当てられます。新しいタイプを割り当てる必要があるとすぐに、次の論理メモリブロックの先頭に揃えられます。次の論理ブロックは、プロセッサによって異なります。一部のプロセッサは8ビット境界に整列できますが、他のプロセッサは16ビット境界にしか整列できません。
Test3では、各メンバーは前のメンバーとは異なるタイプであるため、メモリ割り当ては8 *(システムの最小論理ブロックサイズ)になります。あなたの場合、最小ブロックサイズは2バイト(16ビット)なので、test3のサイズは8 * 2 = 16です。
8ビットブロックを割り当てることができるシステムでは、サイズは8になると思います。
その動作の多くは実装(コンパイラ)で定義されているため、ビットフィールドには注意してください。
C++ 03から、9.6ビットフィールド(163ページ):
クラスオブジェクト内のビットフィールドの割り当ては、実装によって定義されます。ビットフィールドの配置は実装によって定義されます。ビットフィールドは、アドレス指定可能なアロケーションユニットにパックされます。 [注:ビットフィールドは、一部のマシンではアロケーションユニットにまたがっており、他のマシンではまたがっていません。ビットフィールドは、一部のマシンでは右から左に割り当てられ、他のマシンでは左から右に割り当てられます。 ]
つまり、これはコンパイラのバグではなく、動作の標準的な定義が不足しているということです。
うわー、それは驚くべきことです。 GCC 4.2.4では、CモードとC++モードの両方で、結果はそれぞれ1、4、および4になります。これが私が使用したC99とC++の両方で動作するテストプログラムです。
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include <stdio.h>
struct test1 {
bool test_a:1;
bool test_b:1;
bool test_c:1;
bool test_d:1;
bool test_e:1;
bool test_f:1;
bool test_g:1;
bool test_h:1;
};
struct test2 {
int test_a:1;
int test_b:1;
int test_c:1;
int test_d:1;
int test_e:1;
int test_f:1;
int test_g:1;
int test_h:1;
};
struct test3 {
int test_a:1;
bool test_b:1;
int test_c:1;
bool test_d:1;
int test_e:1;
bool test_f:1;
int test_g:1;
bool test_h:1;
};
int
main()
{
printf("%zu %zu %zu\n", sizeof (struct test1), sizeof (struct test2),
sizeof (struct test3));
return 0;
}
一般的な観察として、1ビットの符号付きint
はあまり意味がありません。確かに、おそらく0を格納する方法を理解できますが、それから問題が始まります。
2の補数であっても、1ビットは符号ビットである必要がありますが、使用できるのは1ビットだけです。したがって、それを符号ビットとして割り当てると、実際の値のビットは残りません。 Steve Jessopがコメントで指摘しているように、2の補数を使用すればおそらく-1を表すことができますが、それでも0と-1しか表現できない「整数」データ型はかなり奇妙なものだと思います。
私にとって、このデータ型は意味がありません(または、Steveのコメントを考えると、little)。
使用する unsigned int small : 1;
符号なしにするには、値0と1をあいまいさのない方法で格納できます。
#include <iostream>
using namespace std;
bool ary_bool4[10];
struct MyStruct {
bool a1 :1;
bool a2 :1;
bool a3 :1;
bool a4 :1;
char b1 :2;
char b2 :2;
char b3 :2;
char b4 :6;
char c1;
};
int main() {
cout << "char size:\t" << sizeof(char) << endl;
cout << "short int size:\t" << sizeof(short int) << endl;
cout << "default int size:\t" << sizeof(int) << endl;
cout << "long int size:\t" << sizeof(long int) << endl;
cout << "long long int size:\t" << sizeof(long long int) << endl;
cout << "ary_bool4 size:\t" << sizeof(ary_bool4) << endl;
cout << "MyStruct size:\t" << sizeof(MyStruct) << endl;
// cout << "long long long int size:\t" << sizeof(long long long int) << endl;
return 0;
}
char size: 1
short int size: 2
default int size: 4
long int size: 4
long long int size: 8
ary_bool4 size: 10
MyStruct size: 3
「サミュエル・P・ハービソン、ガイ・L・スティール] C Aリファレンス」より:
問題:
「コンパイラは、ビットフィールドの最大サイズに自由に制約を課し、ビットフィールドが通過できない特定のアドレス指定境界を指定できます。」
標準内で実行できる操作:
「パディングを提供するために、名前のないビットフィールドを構造体に含めることもできます。」
「名前のないビットフィールドに長さ0を指定すると、特別な意味があります。これは、前のビットフィールドが含まれる領域にビットフィールドをこれ以上パックしないことを示します...ここでの領域は、暗黙的に定義されたストレージユニットを意味します。」
これはあなたが期待するものですか、それともコンパイラのバグですか?
したがって、C89、C89、修正I、C99内では、バグではありません。 C++についてはわかりませんが、動作は似ていると思います。