在二进制协议中,我需要发送8个字节。这些字节可以包含8或16位长的整数,也可以包含1,2或3位长的标志。
为了简化它,我更喜欢使用结构:
struct MakeCoffeeCmd
{
UINT8 sugar : 2;
UINT8 milk : 1;
UINT16 liters;
};
所以我可以像这样使用它:
cmd.sugar = 1;
cmd.milk = 0;
cmd.liters = 42;
send(cmd);
问题是:糖,牛奶和升在8字节数组中定义了位置,每个未使用的位必须设置为1.
现在,我使用:
UINT8 cmd[8];
memset(&cmd, ~0, sizeof(cmd));
cmd[1] &= sugar << 4;
cmd[1] &= milk << 1;
*((UINT16*)(cmd + 3)) = liters;
send(cmd);
我想创建一个8字节长的结构。由于原因,我只关心第二个和第三个字节,所有其他字节必须设置为0xFF。
应该如下所示:0xFF [Byte1] [Byte2] 0xFF 0xFF 0xFF 0xFF 0xFF
我试过这样,但看起来太丑了。
struct mystruct
{
mystruct() : should_be_ff(0xFF), should_also_be_ff(0xFF), sould_be_ff_too(0xFFFFFFFF) {}
UINT8 should_be_ff;
UINT16 important_values;
UINT8 should_also_be_ff;
UINT32 should_be_ff_too;
}
我可以使用位字段进行填充,但是我无法设置正确的值。
我更喜欢这样的事情:
struct mystruct
{
0xFF;
UINT16 important_values;
0xFFFFFF;
}
有什么想法吗?
我需要一些专有的二进制协议,我无法改变。这只是一个例子,有更复杂的结构,包括标志和位字段。在数组中使用它们会很难看。
我已修改打包(希望)消除填充错误。
答案 0 :(得分:8)
我想创建一个8字节长的结构。
您的结构可能不是8个字节长。你可以在成员之间填充,也可以在最后填充。
没有标准方法可以保证结构的大小为8个字节。
如果您只需要8个字节,则可以使用数组:
uint8_t arr[8]; // exactly 8 bytes
memset(arr, ~0, sizeof arr); // set all bits to 1 i.e. every byte to 0xff
uint16_t foo = 123u; // some important 2-byte value
memcpy(arr + 1, &foo, sizeof foo); // copy the 2-byte value to the second and third index
请记住,字节的顺序取决于架构的字节顺序。
您当然可以使用这样的结构来表示您自己的应用程序中的协议消息。但要根据协议发送它,必须先将其转换为数组。必须逐场完成。由于填充和别名问题,转换不会在平台上正确执行。我建议使用char
数组,因为char
类型有关于别名的特殊规则,这使得它们更易于使用。
要将struct实例的未使用位设置为1,最简单的解决方案可能是memset
:
MakeCoffeeCmd object;
memset(&object, ~0, sizeof object);
之后,您可以设置使用的字段。然后将每个字段复制到数组中正确的插槽。
答案 1 :(得分:1)
怎么样:
struct mystruct
{
UINT8 ignore1;
std::array<UINT8, 2> data;
std::array<UINT8, 5> ignore2;
mystruct()
: ignore1(0xFF)
{
ignore2.fill(0xFF);
}
};
如果std :: array有一个填充构造函数,那么它就更清晰了。
答案 2 :(得分:1)
使用gcc
,您可以执行此操作,以实施紧密包装:
struct __attribute__((__packed__)) my_struct
{
uint8_t field1=0xff;
uint16_t field2=0xabcd; // or whatever you need
uint8_t field3=0xff;
uint32_t field4=0xffffffff;
};
有关使用__attribute__
的详细信息,请查看文档:
https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#Common-Type-Attributes
答案 3 :(得分:0)
我有这样的想法:
struct mystruct{
mystruct(uint16_t impval=0){
memset(m_data,0xff,sizeof(m_data));
important() = impval;
}
void* data(){
return m_data;
}
uint16_t& important(){
return *reinterpret_cast<uint16_t*>(m_data+1);
}
private:
uint8_t m_data[8];
};
当然,它可以做得更好,更便携,但没有时间atm
答案 4 :(得分:0)
这个选项怎么样:
uint32_t arr[2];
uint32_t inportant_flag = 123u;
arr[0] = 0xFF0000FF + (inportant_flag<<8);
arr[1] = 0xFFFFFFFF;