假设我有以下数据结构(伪代码):
struct
{
uint8 id;
bool failure;
uint8 value;
}
现在假设我希望以以下方式将数据存储在内存中: 位7-6:id 位5:故障 位4-0:值
在C/C++/Visual Studio中是否有任何方法可以实现这一点?我知道你可以在Ada中实现它,但那没什么用。
编辑:抱歉没有表达清楚,我确实需要特定的内存布局。此结构将用于通过串行通道发送的消息,并且需要符合接口规范。
假设我有以下数据结构(伪代码):
struct
{
uint8 id;
bool failure;
uint8 value;
}
struct
{
uint8 id : 2;
bool failure : 1;
uint8 value : 5;
};
struct
{
int id :2;
bool failure:1;
int value :5;
}
value
的位数上是正确的,但数据类型都是错误的(问题要求无符号)。 - Ben Voigt针对原始数据的答案,你需要将数据放在一个 uint8_t
变量中,并使用位掩码和位移操作来提取数据,以下是一个示例实现:
class MyData
{
private:
uint8_t data;
public:
MyData() : data(0) {}
MyData(uint8_t id, bool failure, uint8_t value) : data(0)
{
Id(id);
Failure(failure);
Value(value);
}
uint8_t Id()
{
return (data>>6);
}
void Id(uint8_t id)
{
data &= 0x3F;
data |= ((id&0x3)<<6);
}
bool Failure()
{
return (data & 0x20);
}
void Failure(bool failure)
{
if(failure)
{
data |= 0x20;
}
else
{
data &= 0xDF;
}
}
uint8_t Value()
{
return (data & 0x0F);
}
void Value(uint8_t val)
{
data &= 0xF0;
data|=(val&0xF);
}
};
ox3F==00111111b
),and运算符清除掩码中为0的部分,并不触及其他位。指令2使用or运算符将(先前已清除的)高位设置为新值,并保留原始值,因为低位为0且a|0==a
。这可以使用位域来实现。在这种特定情况下,C++代码如下:
struct
{
uint8 value : 5; // bits 0-4
bool failure : 1; // bit 5
uint8 id : 2; // bit 6-7
};
注意:一定要检查编译器文档,因为位序和内存填充可能会影响可移植性。有关更多信息,请参见http://en.wikipedia.org/wiki/Bit_field或在Google上搜索C++位字段。
有特定于平台的方法可以实现结构体打包。但如果你想遵循规范,就必须手动将其打包到 uint8 缓冲区或类似的缓冲区中。编译器会尊重其他提出的解决方案中字段的大小,但它可以以任何方式将它们打包在结构体内部。例如,为了进行速度优化,它可能在结构体字段之间放置未使用的填充。
[class.bit]
部分:“类对象内位域的分配是实现定义的。位域的对齐是实现定义的。” - Ben Voigtuint16_t
声明一个20位的位域,则效果是有4位仅用于填充,并且不参与值,即上面示例中的b
仅包含16个有效位。位域声明中的类型确实很重要。 - David Rodríguez - dribeas