我需要创建一个带位域的结构来封装来自硬件的一些数据。假设我使用特定于编译器的机制来强制执行打包和排序,是否可以创建类似于以下的结构(在语法上不正确):
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。
答案 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,如协议所指定的那样。