如何获取结构中的位数组?

我正在思考(因此我正在寻找一种方法来学习这个, 而不是一个更好的解决方案 ),如果有可能在结构中获得一个位数组。

让我举一个例子来certificate。 想象一下这样的代码:

#include  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  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]:1unsigned int bits:1[4]或类似的东西无济于事。 我最好的猜测是typedef unsigned int bit:1; 并使用bit作为类型,但仍然无法正常工作。

我的问题是,这样的事情可能吗? 如果有,怎么样? 如果没有,为什么不呢? 1位unsigned int是一个有效的类型,那么为什么你不能得到它的数组呢?

再一次,我不想替换它,我只是想知道这样的事情是如何可能的。

PS我将其标记为C ++,尽管代码是用C语言编写的,因为我认为这种方法在两种语言中都存在。 如果有一种C ++特定的方法(通过使用语言结构,而不是库),我也有兴趣知道。

更新:我完全知道我可以自己做位操作。 我过去做过一千次。 我对一个使用数组/向量代替并进行位操作的答案不感兴趣。 我只是在考虑这种结构是否可行,而不是替代方案。

更新:不耐烦的答案(感谢neagoegab):

代替

 typedef unsigned int bit:1; 

我可以用

 typedef struct { unsigned int value:1; } bit; 

正确使用#pragma pack

不可能这样的结构是不可能的 ( 这里 )不可能

可以尝试这样做,但结果将是一位存储在一个字节中

 #include  #include  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] < 

输出:

 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  #include  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 < 

在C ++中,您使用std::bitset<4> 。 这将使用最少数量的单词进行存储,并隐藏您的所有屏蔽。 将C ++库与语言分开是非常困难的,因为在标准库中实现了很多语言。 在C中,没有直接的方法来创建像这样的单个位数组,而是创建一个四位元素或手动操作。

编辑:

1位unsigned int是一个有效的类型,那么为什么你不能得到它的数组呢?

实际上除了创建struct / class成员的上下文之外,你不能在任何地方使用1位无符号类型。 那时它与其他类型有很大的不同,它不会自动跟随你可以创建它们的数组。

C ++将使用std::vectorstd::bitset

在C中,为了模拟std::vector语义,你使用这样的结构:

 struct Bits { Word word[]; size_t word_count; }; 

其中Word是一个实现定义的类型,其宽度等于CPU的数据总线; 后面使用的wordsize大小等于数据总线的宽度。

例如,对于32位计算机, Worduint32_fast_t ,对于64位计算机,则是uint32_fast_t ; 对于32位计算机, wordsize为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添加可resize,请创建一个resize函数,该函数在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; } 

您还可以使用整数数组(整数或长整数)来构建任意大的位掩码。 select()系统调用将此方法用于其fd_set类型; 每个位对应于编号的文件描述符(0..N)。 定义宏:FD_CLR清除一位,FD_SET设置一位,FD_ISSET测试一位,FD_SETSIZE是总位数。 宏自动确定要访问的数组中的哪个整数以及整数中的哪个位。 在Unix上,请参阅“sys / select.h”; 在Windows下,我认为它在“winsock.h”中。 您可以使用FD技术为位掩码创建自己的定义。 在C ++中,我想你可以创建一个位掩码对象并重载[]运算符来访问各个位。

您可以使用结构指针创建位列表。 这将使用每位写入多于一点的空间,因为它将每位使用一个字节(用于地址):

 struct bitfield{ unsigned int bit : 1; }; struct bitfield *bitstream; 

然后呢:

 bitstream=malloc( sizeof(struct bitfield) * numberofbitswewant ); 

您可以像这样访问它们:

 bitstream[bitpointer].bit=...