protobuf序列化与反序列化
做个项目,参数保存使用protobuf协议序列化后写到flash,读出后反序列化赋值。
// <! 参数1
message Param1_t
{
int32 age = 1; // <! 日龄
int32 weight = 2 [default = 100]; // <! 体重
}
message Param2_t
{
int32 age = 1; // <! 日龄
int32 weight = 2; // <! 体重
}
#define Param_t_Default {10, 0}
typedef struct _Pig_t {
int32 age; // <! 日龄
int32 weight; // <! 体重
} Pig_t;
Pig_t pig = Param_t_Default;
消息类型中原始数据类型默认值是0,但在程序其他地方定义默认值,每次读时候都会先把默认值赋值给接收消息体的结构体变量。
有次设置年龄为0(日龄不可能是0的),保存后,再次读出确实是10,为什么?一直找不到原因。用protobuf,没有对序列化与反序列化原理深入研究。
- 在 Protobuf 2 中,消息的字段可以加 required 和 optional 修饰符,也支持 default 修饰符指定默认值。默认配置下,一个 optional 字段如果没有设置,或者显式设置成了默认值,在序列化成二进制格式时,这个字段会被去掉,导致反序列化后,无法区分是当初没有设置还是设置成了默认值但序列化时被去掉了,即使 Protobuf 2 对于原始数据类型字段都有 hasXxx() 方法,在反序列化后,对于这个“缺失”字段,hasXxx() 总是 false——失去了其判定意义。
- 在 Protobuf 3 中,更进一步,直接去掉了 required 和 optional 修饰符,所有字段都是 optional 的, 而且对于原始数据类型字段,压根不提供 hasXxx() 方法。来自 Google 的 GRPC 核心成员Eric Anderson 在 StackOverflow 网站很好的解释了这个设计决策的原因:Why required and optional is removed in Protocol Buffers 3
原因找到,r日龄设置默认值0后,序列化会直接把这字段去掉,反序列化找不到数据,不会赋值,也就是这值是在序列化前默认的值。体重设置默认100,序列化保存后在反序列化读出来体重值是0.
解决方法:Param_t_Default定义的默认值要与protobuf定义参数默认值一样