C/C++ 中的嵌套位域

Nested bitfields in C/C++

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

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 需要从字节边界开始。我想知道是否有其他技巧可以实现位域的 "nesting"。

为了详细说明我之前的评论,这些内容应该允许您想要的访问方式。尽管以一种远非优雅的方式:

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 位域总是会导致代码效率低下且容易出现竞争。

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

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;

在 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;
};

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