如何在结构中获得位数组

How to get array of bits in a structure?

本文关键字:数组 结构      更新时间:2023-10-16

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

让我用一个例子来说明。想象这样一个代码:

#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("%un", a.bit0);
    printf("%un", a.bit1);
    printf("%un", a.bit2);
    printf("%un", 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("%un", b.bits[i]);
    return 0;
}

我试图在struct B中声明bitsunsigned int bits[4]:1unsigned int bits:1[4]或类似的东西,但无济于事。我最好的猜测是typedef unsigned int bit:1;和使用bit作为类型,但仍然不起作用。

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

再说一遍,我不想要一个替代品,我只是想知道这样的事情是怎么可能的。

注:虽然代码是用C编写的,但我将其标记为c++,因为我假设该方法在两种语言中都存在。如果有一种c++特有的方法(通过使用语言结构,而不是库),我也很想知道。

更新:我完全知道我可以自己做位操作。我以前做过上千次了。我对一个回答不感兴趣,说使用数组/向量,而不是做位操作。

我只是在想这个CONSTRUCT是否可行,而不是另一种选择。

更新:给没有耐心的人的答案(感谢neagoegab):

不是

typedef unsigned int bit:1;

我可以用

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

正确使用#pragma pack

NOT POSSIBLE - 这样的构造是不可能的(这里) - 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;
    }
}

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

编辑:

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

实际上,除了创建结构/类成员的上下文中,您不能在任何地方使用1位unsigned类型。在这一点上,它与其他类型是如此的不同,以至于你不能自动创建一个数组

c++将使用std::vector<bool>std::bitset<N>

在C语言中,为了模拟std::vector<bool>语义,您可以使用这样的结构体:

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

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

。32位机器的Worduint32_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>添加可调整大小,请创建一个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("%dn", (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指针创建位列表。但是,这样每写一个比特就会使用更多的空间,因为它每写一个比特就会使用一个字节(用于地址):

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

之后:

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

你可以这样访问它们:

bitstream[bitpointer].bit=...