序列化和反序列化位域。

6
我收到了一份定义了一组通过串行通信信道传输和接收的消息的文档。我想将传入的消息反序列化为对象,并序列化我的出站消息。在线路上传输的编码已经确定且不可更改,包括头部中的各种位域和不同的有效载荷。
class Message{
int msg_num : 7
int dest_addr : 4
bool SRR : 1
bool IDE : 1
int source_addr : 6
//... and so on...
}

我研究了使用protobufs,但是它们的变长编码方法已经确定。我还看了boost-serialization,但根据我目前所读的内容,那里的编码方式并不完全清楚。

因此,有几个问题:

  • 我可以使用boost-serialization将我的字节流转换为对象吗?
  • 为了避免编写自己的序列化例程(维护混乱),是否有一种首选机制来完成我的任务(例如,自定义boost-serialization Archive,或者其他我尚未发现的方法)?

“int msg_num : 7” 的意思是该字段是一个7位整数吗? - grieve
是的。": num" 表示位域的长度。 - jdt141
我觉得这个问题很难回答,因为只展示了打包后的表示形式,而没有展示您想要序列化和反序列化的未打包消息对象。 - Matt T
如果你要跨平台,比如从Wintel到Sun Sparc,这可能会变得非常混乱和丑陋。 - JimR
2个回答

1

我认为你不会找到一个易于使用的序列化器来匹配你所寻找的自定义协议。但是看起来你拥有的原语集合(int,bool + size)足够简单,可以编写自己的解码器/编码器。只需根据接收到的消息生成C/C++代码即可。生成一个可编译代码的描述应该是相当简单的任务。这应该是在编译时进行的自动化生成-类似于protobuf/Corba正在做的事情。

例如:从规范中:

class Message{
    int msg_num : 7
    int dest_addr : 4
    bool SRR : 1
    bool IDE : 1
    int source_addr : 6
    //... and so on...
}

转换器可以编写一个类似于以下内容(抽象符号和假设 MSB)的函数:

解码器:

m = new Message()
{
    long long val = 0
    for(int i=0; i<7; i++) {
        val <<= 8
        val += nextByte()    
    }
    m.msg_num = val
}
{
    long long val = 0
    for(int i=0; i<4; i++) {
        val <<= 8
        val += nextByte()    
    }
    m.dest_addr = val
}
{
    int val = nextByte()
    m.SRR = val
}
{
    int val = nextByte()
    m.IDE = val
}
{
    long long val = 0
    for(int i=0; i<6; i++) {
        val <<= 8
        val += nextByte()    
    }
    m.source_addr = val
}
// and so on

编码器:

{
    long long val = m.msg_num
    for(int i=0;i<7;i++) {
        writeByte(val & 0xFF)
        val >>= 8
    }
}
{
    long long val = m.dest_addr
    for(int i=0;i<4;i++) {
        writeByte(val & 0xFF)
        val >>= 8
    }
}
....

这应该很容易生成,也是确保编码自定义的最简单方法。


据我所知,标准并不强制实现使用与 int 不同的任何类型来表示位域(即使您在代码中编写了不同的类型,例如 char 或 bool),而且标准也将位域的内存顺序(MSB 到 LSB 或反之)留给实现。因此,按字节序列化可能会对位域造成问题。 - selalerer
1
当然。我的答案更多是一个例子,而不是解决方案 - 具体实现应该反映协议,取决于字节如何通过电线发送。这更多是为了展示如何完成:生成转换代码应该可以解决问题。 - Jarek Potiuk

0

如果您只限于单个平台(即仅限于单个字节顺序),并且消息是POD类型,则可以将消息声明为primitive

否则,至少在boost.serialization中,您将不得不编写代码,即“序列化例程”。它支持字节顺序转换,至少如此。

[编辑] 错了,不是primitive,我迷失在序列化文档的深处了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接