简体   繁体   English

序列化/反序列化 c++ 中的位域结构

[英]Serializing/deserializing a bitfield structure in c++

I have a我有一个

typedef struct {
    uint32_t  Thread: HTHREAD_BUS_WIDTH; 
    uint32_t Member: 3;                  
    uint32_t Proxy:3;  
// Other members, fill out 32 bits                 
} MyStruct;

that I must transfer from one system to another as an item of a buffer comprising 32-bit words.我必须从一个系统传输到另一个系统作为包含 32 位字的缓冲区的一项。

What is the best way to serialize the struct, and on the other side, to deserialize it?序列化结构以及反序列化它的最佳方法是什么? "best" means here safe casting, and no unneeded copying. “最佳”在这里意味着安全铸造,没有不必要的复制。 For one direction of casting, I have found (as member function)对于一个铸造方向,我发现(作为成员函数)

int &ToInt() {
    return *reinterpret_cast<int *>(this);}

Is there similar valid casting in the other way round, ie from integer to MyStruct;是否有类似的有效转换,即从 integer 到 MyStruct; the best would be as a member function?最好的成员是 function?

How can I define which bit means which field?如何定义哪个位表示哪个字段? (It may even the case, that the deserialization happens in another program, in another language, in little/big endian systems? (甚至可能是反序列化发生在另一个程序、另一种语言、小/大端系统中?

How can I define which bit means which field?如何定义哪个位表示哪个字段?

You cannot.你不能。 You have no control over the layout of bitfields.您无法控制位域的布局。

"best" means here safe casting, and no unneeded copying. “最佳”在这里意味着安全铸造,没有不必要的复制。

There is no portable safe cast that could avoid copying.没有可以避免复制的便携式安全演员。


A portable way to serialise bitfields is to manually shift into an integer, in the desired order.序列化位域的一种可移植方法是按所需顺序手动转换为 integer。 For example:例如:

MyStruct value = something;
uint32_t out = 0;
out |= value.Thread;
out << HTHREAD_BUS_WIDTH;
out |= value.Member;
out << 3;
out |= value.Proxy;

In the shown example, the least significant bits contain the field Proxy while the other fields are adjacent in more significant bits.在所示示例中,最低有效位包含字段Proxy ,而其他字段在更高有效位中相邻。

Of course, in order to serialise this generated integer correctly, just like serialising any integer, you must take endianness into consideration.当然,为了正确序列化这个生成的 integer,就像序列化任何 integer 一样,您必须考虑字节顺序。 Serialisation of an integer can be portably implemented by repeatedly shifting the integer, and copying the bytes in order of significance into an array. integer 的序列化可以通过重复移动 integer 并将字节按重要性顺序复制到数组中来实现。

If you need to read from other system which might have different endianess you cannot rely on a portable bitfield.如果您需要从可能具有不同字节顺序的其他系统读取,则不能依赖可移植位域。 A solution is to "expanse" your structure so that each field is serialyzed as a 32 bit value in the "transport" buffer.一种解决方案是“扩展”您的结构,以便每个字段在“传输”缓冲区中序列化为 32 位值。 A safe implementation could be something like:一个安全的实现可能是这样的:

typedef struct {
    uint32_t  Thread: HTHREAD_BUS_WIDTH; 
    uint32_t Member: 3;                  
    uint32_t Proxy:3;  
// Other members, fill out 32 bits                 
   std::vector<uint32_t > to_buffer() const;
} MyStruct;

Implementation of to_buffer(): to_buffer()的实现:

std::vector<uint32_t > MyStruct::to_buffer() const
{
   std::vector<uint32_t> buffer;
   buffer.push_back((uint32_t )(Thread);
   buffer.push_back((uint32_t )(Member);
   buffer.push_back((uint32_t )(Proxy);
   // push other members

  return buffer;
}

then on the reception side you can do the "buffer" to struct.然后在接收端你可以做“缓冲区”来构建。

If you do not want to expanse the fields that do not use 32 bits you can always implement you own packing function by shifting and masking bits eg:如果您不想扩展不使用 32 位的字段,您始终可以通过移位和屏蔽位来实现自己的打包 function,例如:

uint32_t menber_and_procy = (Member << 3) | proxy; // and so one for other members.

It is much more error prone.它更容易出错。

From my own experience, if communication bandwith is not an issue, relying on "text like" content is a better choice (no endianess issues and very easy to debug).根据我自己的经验,如果通信带宽不是问题,那么依靠“类似文本”的内容是更好的选择(没有字节序问题并且非常容易调试)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM