38

ビットフィールドでテストを行ったところ、驚くべき結果が得られました。

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、ところで...)

4

6 に答える 6

31

コンパイラは、test3 のすべてのメンバーを整数サイズの境界に配置しました。ブロックが特定のタイプ (整数ビットフィールドまたはブールビットフィールド) に使用されると、コンパイラは次の境界まで別のタイプのビットフィールドを割り当てません。

バグだと思います。おそらく、システムの基礎となるアーキテクチャと関係があります。

編集:

C++ コンパイラは、次のようにビット フィールドをメモリに割り当てます。同じ型の連続するビット フィールド メンバーがいくつか連続して割り当てられます。新しい型を割り当てる必要があるとすぐに、次の論理メモリ ブロックの先頭に配置されます。次の論理ブロックは、プロセッサによって異なります。一部のプロセッサは 8 ビット境界に整列できますが、他のプロセッサは 16 ビット境界にしか整列できません。

test3 では、各メンバーはその前のメンバーとは異なるタイプであるため、メモリ割り当ては 8 * (システムの最小論理ブロック サイズ) になります。あなたの場合、最小ブロック サイズは 2 バイト (16 ビット) であるため、test3 のサイズは 8*2 = 16 です。

8 ビット ブロックを割り当てることができるシステムでは、サイズは 8 になると予想されます。

于 2008-11-21T10:40:22.507 に答える
20

その動作の多くは実装 (コンパイラ) で定義されているため、ビットフィールドには注意してください。

C++03 から、9.6 ビットフィールド (pg. 163):

クラス オブジェクト内のビット フィールドの割り当ては実装定義です。ビットフィールドのアライメントは実装定義です。ビットフィールドは、アドレス指定可能なアロケーション ユニットにパックされます。[注: ビットフィールドは、一部のマシンではアロケーション ユニットにまたがり、他のマシンではまたがりません。ビットフィールドは、一部のマシンでは右から左に割り当てられ、他のマシンでは左から右に割り当てられます。]

つまり、これはコンパイラのバグではなく、コンパイラがどのように動作するかについての標準的な定義が欠如しているということです。

于 2008-11-21T13:23:03.430 に答える
7

うわー、それは驚くべきことです。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;
}
于 2008-11-21T10:42:39.087 に答える
5

一般的な観察として、int1 ビットの符号付きはあまり意味がありません。確かに、おそらく 0 を格納する方法を理解できるでしょうが、そこから問題が始まります。

2 の補数であっても、1 ビットは符号ビットでなければなりませんが、操作できるビットは 1 ビットしかありません。したがって、それを符号ビットとして割り当てると、実際の値用にビットが残っていません。Steve Jessop がコメントで指摘しているように、2 の補数を使用するとおそらく -1 を表すことができますが、それでも 0 と -1 しか表すことができない「整数」データ型はかなり奇妙なことだと思います。

私には、このデータ型は意味がありません (または、Steve のコメントを考えるとほとんど意味がありません)。

を使用unsigned int small : 1;して符号なしにすると、値 0 と 1 を明確な方法で格納できます。

于 2008-11-21T11:17:19.843 に答える
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
于 2010-05-28T13:34:16.660 に答える
0

「サミュエル P. ハービソン、ガイ L. スティール] CA リファレンス」より:

問題:

「コンパイラは、ビットフィールドの最大サイズに自由に制約を課し、ビットフィールドが交差できない特定のアドレス指定境界を指定できます。」

標準内で実行できる操作:

「パディングを提供するために、名前のないビットフィールドを構造体に含めることもできます。」

「名前のないビットフィールドの長さ0を指定すると、特別な意味があります。これは、前のビットフィールドがあった領域にこれ以上ビットフィールドをパックしないことを示しています...ここでの領域は、いくつかの実装を意味します。定義されたストレージユニット」

これはあなたが期待するものですか、それともコンパイラのバグですか?

したがって、C89 内では、修正 I を含む C89、C99 - これはバグではありません。C++についてはわかりませんが、動作は似ていると思います。

于 2015-02-24T10:42:42.517 に答える