我正在思考(因此我正在寻找一种方法来学习这个,而不是更好的解决方案),如果有可能在结构中获得一个位数组。
让我举一个例子来证明。想象一下这样的代码:
#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;
}
在这段代码中,我们在一个struct中打包了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;
}
我尝试在bits
中将struct B
声明为unsigned int bits[4]:1
或unsigned int bits:1[4]
或类似的内容无济于事。我最好的猜测是typedef unsigned int bit:1;
并使用bit
作为类型,但仍然无效。
我的问题是,这样的事情可能吗?如果有,怎么样?如果没有,为什么不呢? 1位unsigned int是一个有效的类型,那么为什么你不能得到它的数组呢?
同样,我不想替换这个,我只是想知道这样的事情是如何可能的。
P.S。我将其标记为C ++,虽然代码是用C语言编写的,因为我认为这种方法在两种语言中都存在。如果有一种特定于C ++的方法(通过使用语言结构,而不是库),我也有兴趣知道。
更新:我完全知道我可以自己做位操作。我过去做过一千次。我对使用数组/向量代替并进行位操作的答案不感兴趣。我只是在考虑这种结构是否可行,而不是替代方案。
更新:回答不耐烦(感谢neagoegab):
而不是
typedef unsigned int bit:1;
我可以用
typedef struct
{
unsigned int value:1;
} bit;
正确使用#pragma pack
答案 0 :(得分:9)
NOT POSSIBLE - 像这样的构造不可能(here) - NOT POSSIBLE
可以尝试这样做,但结果是一位存储在一个字节中
#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;
}
}
答案 1 :(得分:6)
在C ++中,您使用std::bitset<4>
。这将使用最少数量的单词进行存储,并隐藏您的所有屏蔽。将C ++库与语言分开是非常困难的,因为在标准库中实现了很多语言。在C中,没有直接的方法来创建像这样的单个数组,而是创建一个四位元素或手动操作。
编辑:
1位unsigned int是一个有效的类型,所以为什么你不能这样做 得到它的数组?
实际上,除了创建struct / class成员的上下文之外,你不能使用1位无符号类型。那时它与其他类型有很大的不同,它不会自动跟随你可以创建它们的数组。
答案 2 :(得分:4)
C ++会使用std::vector<bool>
或std::bitset<N>
。
在C中,为了模拟std::vector<bool>
语义,你可以使用这样的结构:
struct Bits {
Word word[];
size_t word_count;
};
其中Word
是一个实现定义的类型,其宽度等于CPU的数据总线;稍后使用的wordsize
等于数据总线的宽度。
E.g。对于32位计算机,Word
为uint32_fast_t
,对于64位计算机,uint64_fast_t
为wordsize
;
对于32位计算机,GET_BIT(bits, bit) (((bits)->)word[(bit)/wordsize] & (1 << ((bit) % wordsize)))
为32,对于64位计算机,则为{64}。
使用函数/宏来设置/清除位。
要提取一点,请使用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>
。
要根据realloc
添加可调整大小,请设置一个调整Bits.word
上Bits.word_count
的调整大小功能,并相应地更改{{1}}。确切的细节仍然存在问题。
同样适用于位索引的正确范围检查。
答案 3 :(得分:2)
这是滥用,并依赖于扩展...但它对我有用:
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;
}
答案 4 :(得分:0)
您还可以使用整数数组(整数或长整数)来构建任意大的位掩码。 select()系统调用将此方法用于其fd_set类型;每个位对应于编号的文件描述符(0..N)。定义宏:FD_CLR清除一位,FD_SET设置一位,FD_ISSET测试一位,FD_SETSIZE是总位数。宏自动确定要访问的数组中的哪个整数以及整数中的哪个位。在Unix上,请参阅“sys / select.h”;在Windows下,我认为它在“winsock.h”中。您可以使用FD技术为位掩码创建自己的定义。在C ++中,我想你可以创建一个位掩码对象并重载[]运算符来访问各个位。
答案 5 :(得分:-1)
您可以使用结构指针创建位列表。这将使用每位写入多于一点的空间,因为它将每位使用一个字节(用于地址):
struct bitfield{
unsigned int bit : 1;
};
struct bitfield *bitstream;
之后:
bitstream=malloc( sizeof(struct bitfield) * numberofbitswewant );
您可以像这样访问它们:
bitstream[bitpointer].bit=...