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

时间:2011-11-15 21:13:47

标签: c++ c internals

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

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

#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]:1unsigned 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

6 个答案:

答案 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位计算机,Worduint32_fast_t,对于64位计算机,uint64_fast_twordsize; 对于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.wordBits.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=...