C / C ++中的嵌套位域

时间:2015-03-20 16:48:05

标签: c++ c bit-fields

我需要创建一个带位域的结构来封装来自硬件的一些数据。假设我使用特定于编译器的机制来强制执行打包和排序,是否可以创建类似于以下的结构(在语法上不正确):

typedef struct _BYTE_OF_DATA
{
    uint8_t Reserved1 : 2;
    struct
    {
        uint8_t BitWithSomeMeaning : 1;
        uint8_t BitWithSomeOtherMeaning : 1;
    } BitsWithMeaning;
    uint8_t Reserved2 : 4;
} BYTE_OF_DATA, *PBYTE_OF_DATA;

static_assert(sizeof(BYTE_OF_DATA) == 1, "Incorrect size");

然后可以按如下方式访问:

BYTE_OF_DATA byteOfData;

byteOfData.Reserved1 = 1;
byteOfData.BitsWithMeaning.BitWithSomeOtherMeaning = 0;

我上面描述的确切方案不起作用,因为我猜结构BitsWithMeaning需要从字节边界开始。我想知道是否还有其他一些技巧可以实现这一目标"嵌套" bitfields。

3 个答案:

答案 0 :(得分:7)

要详细说明我以前的评论,这些内容应该允许您想要的访问风格。虽然远非优雅的方式:

typedef union _BYTE_OF_DATA {
    struct {
        uint8_t Reserved1 : 2;
        uint8_t : 2;
        uint8_t Reserved2 : 4;
    };
    struct {
        uint8_t : 2;
        uint8_t BitWithSomeMeaning : 1;
        uint8_t BitWithSomeOtherMeaning : 1;
        uint8_t : 4;
    } BitsWithMeaning;
} BYTE_OF_DATA, *PBYTE_OF_DATA;

我个人更喜欢传统的字段掩码和位置常量,并手动修改寄存器。我的经验是,以这种方式访问​​易失性I / O位域总会导致效率低下且容易出现竞争的代码。

答案 1 :(得分:1)

在这种情况下你应该使用联合

typedef union _BYTE_OF_DATA {
    uint8_t data;
    struct {
        uint8_t padding1 : 2;
        uint8_t BitWithSomeMeaning : 1;
        uint8_t BitWithSomeOtherMeaning : 1;
        uint8_t padding 2 : 4;
    } BitsWithMeaning;
} BYTE_OF_DATA, *PBYTE_OF_DATA;

static_assert(sizeof(BYTE_OF_DATA) == 1, "Incorrect size");

所以你可以一次性填充数据:

BYTE_OF_DATA myByte;

myByte.data = someotherbyte;

得到意义:

int meaning1 = myByte.BitWithSomeMeaning;
int meaning2 = myByte.BitWithSomeOtherMeaning;

或者反其道而行:

myByte.data = 0; // Put all fields to 0

myByte.BitWithSomeMeaning = 1;
myByte.BitWithSomeOtherMeaning = 0;

int data = myByte.data;

答案 2 :(得分:0)

在C ++中,最简单的解决方案可能是

struct BYTE_OF_DATA
{
    uint8_t bits;
    private:
    struct
    {
        bool getBitWithSomeMeaning() const { return bool(bits&0x20); }
        bool getWithSomeOtherMeaning() const { return bool(bits&0x10); }
        void setBitWithSomeMeaning(bool b);
        void setWithSomeOtherMeaning(bool b);
    } BitsWithMeaning;
};

显然没有保留字段的getter / setter。 Ctor可能应该将这些字段设置为0或1,如协议所指定的那样。