構造体のビット配列を取得できるかどうかを考えていました(したがって、これを学習する方法を探していますそしてより良い解決策ではありません)。
例を挙げて説明します。そのようなコードを想像してみてください:
#include <stdio.h>
struct A
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
};
int main()
{
struct A a = {1, 0, 1, 1};
printf("%u\n", a.bit0);
printf("%u\n", a.bit1);
printf("%u\n", a.bit2);
printf("%u\n", a.bit3);
return 0;
}
このコードでは、4つの個別のビットが構造体にパックされています。それらは個別にアクセスでき、ビット操作の仕事はコンパイラに任せます。私が疑問に思っていたのは、そのようなことが可能かどうかです。
#include <stdio.h>
typedef unsigned int bit:1;
struct B
{
bit bits[4];
};
int main()
{
struct B b = {{1, 0, 1, 1}};
for (i = 0; i < 4; ++i)
printf("%u\n", b.bits[i]);
return 0;
}
struct B
のbits
をunsigned int bits[4]:1
またはunsigned int bits:1[4]
または同様のものとして宣言しようとしましたが役に立ちませんでした。私の最善の推測は、タイプとしてtypedef unsigned int bit:1;
を使用し、bit
を使用することでしたが、それでも機能しません。
私の質問は、そのようなことは可能ですか?はいの場合、どのように?そうでない場合は、なぜですか? 1ビットのunsignedintは有効な型ですが、なぜその配列を取得できないのでしょうか。
繰り返しますが、私はこれに代わるものを望んでいません、私はそのようなことがどのように可能であるのか疑問に思っています。
P.S.コードはCで記述されていますが、メソッドが両方の言語に存在すると想定しているため、これをC++としてタグ付けしています。それを行うためのC++固有の方法がある場合(ライブラリではなく言語構造を使用することによって)、私も知りたいと思います。
更新:自分でビット演算を実行できることを完全に認識しています。過去に1000回実行しました。代わりに配列/ベクトルを使用してビット操作を実行するという回答には興味がありません。私はこの構造が可能かどうかだけを考えており、代替手段ではありません。
更新:せっかちな人への回答(neagoegabに感謝):
の代わりに
typedef unsigned int bit:1;
使用できます
typedef struct
{
unsigned int value:1;
} bit;
#pragma pack
を適切に使用する
これを試みることもできますが、結果として1ビットが1バイトに格納されます
#include <cstdint>
#include <iostream>
using namespace std;
#pragma pack(Push, 1)
struct Bit
{
//one bit is stored in one BYTE
uint8_t a_:1;
};
#pragma pack(pop, 1)
typedef Bit bit;
struct B
{
bit bits[4];
};
int main()
{
struct B b = {{0, 0, 1, 1}};
for (int i = 0; i < 4; ++i)
cout << b.bits[i] <<endl;
cout<< sizeof(Bit) << endl;
cout<< sizeof(B) << endl;
return 0;
}
出力:
0 //bit[0] value
0 //bit[1] value
1 //bit[2] value
1 //bit[3] value
1 //sizeof(Bit), **one bit is stored in one byte!!!**
4 //sizeof(B), ** 4 bytes, each bit is stored in one BYTE**
バイトから個々のビットにアクセスするための例を次に示します(ビットフィールドのレイアウトは実装に依存することに注意してください)
#include <iostream>
#include <cstdint>
using namespace std;
#pragma pack(Push, 1)
struct Byte
{
Byte(uint8_t value):
_value(value)
{
}
union
{
uint8_t _value;
struct {
uint8_t _bit0:1;
uint8_t _bit1:1;
uint8_t _bit2:1;
uint8_t _bit3:1;
uint8_t _bit4:1;
uint8_t _bit5:1;
uint8_t _bit6:1;
uint8_t _bit7:1;
};
};
};
#pragma pack(pop, 1)
int main()
{
Byte myByte(8);
cout << "Bit 0: " << (int)myByte._bit0 <<endl;
cout << "Bit 1: " << (int)myByte._bit1 <<endl;
cout << "Bit 2: " << (int)myByte._bit2 <<endl;
cout << "Bit 3: " << (int)myByte._bit3 <<endl;
cout << "Bit 4: " << (int)myByte._bit4 <<endl;
cout << "Bit 5: " << (int)myByte._bit5 <<endl;
cout << "Bit 6: " << (int)myByte._bit6 <<endl;
cout << "Bit 7: " << (int)myByte._bit7 <<endl;
if(myByte._bit3)
{
cout << "Bit 3 is on" << endl;
}
}
C++では、std::bitset<4>
を使用します。これにより、最小限の単語数が保存に使用され、すべてのマスキングが非表示になります。言語の多くが標準ライブラリに実装されているため、C++ライブラリを言語から分離するのは非常に困難です。 Cでは、このような単一ビットの配列を直接作成する方法はありません。代わりに、4ビットの要素を1つ作成するか、手動で操作します。
編集:
1ビットのunsignedintは有効な型ですが、なぜその配列を取得できないのでしょうか。
実際には、構造体/クラスメンバーを作成するコンテキスト以外では、1ビットの符号なし型を使用することはできません。その時点では、他のタイプとは非常に異なっているため、自動的には従わないため、それらの配列を作成できます。
C++は_std::vector<bool>
_または_std::bitset<N>
_を使用します。
Cでは、_std::vector<bool>
_セマンティクスをエミュレートするには、次のような構造体を使用します。
_struct Bits {
Word word[];
size_t Word_count;
};
_
ここで、Word
は、CPUのデータバスと幅が等しい実装定義の型です。 wordsize
は、後で使用されるように、データバスの幅と同じです。
例えば。 Word
は32ビットマシンの場合は_uint32_fast_t
_、64ビットマシンの場合は_uint64_fast_t
_です。 wordsize
は、32ビットマシンの場合は32、64ビットマシンの場合は64です。
関数/マクロを使用してビットを設定/クリアします。
ビットを抽出するには、GET_BIT(bits, bit) (((bits)->)Word[(bit)/wordsize] & (1 << ((bit) % wordsize)))
を使用します。
ビットを設定するには、SET_BIT(bits, bit) (((bits)->)Word[(bit)/wordsize] |= (1 << ((bit) % wordsize)))
を使用します。
少しクリアするには、CLEAR_BIT(bits, bit) (((bits)->)Word[(bit)/wordsize] &= ~(1 << ((bit) % wordsize)))
を使用します。
少し反転するには、FLIP_BIT(bits, bit) (((bits)->)Word[(bit)/wordsize] ^= (1 << ((bit) % wordsize)))
を使用します。
_std::vector<bool>
_に従ってサイズ変更可能性を追加するには、_Bits.Word
_でrealloc
を呼び出し、それに応じて_Bits.Word_count
_を変更するサイズ変更関数を作成します。これの正確な詳細は問題として残されています。
同じことがビットインデックスの適切な範囲チェックにも当てはまります。
これは虐待的であり、拡張機能に依存しています...しかしそれは私のために働きました:
struct __attribute__ ((__packed__)) A
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
};
union U
{
struct A structVal;
int intVal;
};
int main()
{
struct A a = {1, 0, 1, 1};
union U u;
u.structVal = a;
for (int i =0 ; i<4; i++)
{
int mask = 1 << i;
printf("%d\n", (u.intVal & mask) >> i);
}
return 0;
}
整数(intまたはlong)の配列を使用して、任意の大きさのビットマスクを作成することもできます。 select()システムコールは、fd_setタイプにこのアプローチを使用します。各ビットは、番号付きのファイル記述子(0..N)に対応します。マクロが定義されています:ビットをクリアするためのFD_CLR、ビットを設定するためのFD_SET、ビットをテストするためのFD_ISSET、およびFD_SETSIZEはビットの総数です。マクロは、配列内のどの整数にアクセスするか、および整数のどのビットにアクセスするかを自動的に判断します。 Unixでは、「sys /select.h」を参照してください。 Windowsでは「winsock.h」にあると思います。 FD手法を使用して、ビットマスクの独自の定義を作成できます。 C++では、ビットマスクオブジェクトを作成し、[]演算子をオーバーロードして、個々のビットにアクセスできると思います。