Protobuf C++中SerializeToString序列化结果不一致问题排查
问题解决:Protobuf序列化反序列化后内容不一致
环境
Qt Creator 12.0.2(基于Qt 6.6.0,GCC 10.3.1 20210422 (Red Hat 10.3.1-1),x86_64)
问题现象
使用Protobuf的SerializeToString序列化自定义DiagnosticData结构体后,将内容反序列化到新结构体再执行序列化,得到的结果与原序列化内容不一致:
- 初始将
velocity设为float类型时,qDebug输出仅显示\r符号; - 改为
string类型后,仍存在部分字段内容缺失的情况。
问题根源
- 字段Setter调用错误:Protobuf会将proto文件中的驼峰命名字段自动转为C++代码中的蛇形命名(下划线分隔小写),你调用了错误的Setter方法,导致
transportWeight和tirePresure字段未被正确赋值,序列化时这两个字段未被写入。 - ParseFromString参数错误:传递
buf->c_str()作为反序列化输入,而Protobuf序列化内容为二进制,可能包含空字节,c_str()会在第一个空字节处截断数据,导致反序列化不完整。 - 二进制内容输出误解:Protobuf序列化结果是二进制数据,包含不可打印字符,直接用qDebug输出会显示转义符(如
\r),并非序列化失败。
修正方案
1. 修正数据生成函数的Setter调用
proto文件中驼峰命名的字段,对应C++的Setter方法为蛇形命名:
DiagnosticData GenerateDiagnosticData() { DiagnosticData dData; int vel = rand() % 55 + 1; int trsmn = rand() % 2 + 1; int w = rand() % 60 + 1; int pres = rand() % 10 + 1; dData.set_velocity(std::to_string(vel)); dData.set_transmission(trsmn); dData.set_transport_weight(w); // 修正为正确的Setter dData.set_tire_pressure(pres); // 修正为正确的Setter return dData; }
2. 修正测试代码的反序列化参数与输出方式
使用栈上std::string避免内存泄漏,直接传递std::string给ParseFromString,并将二进制内容转为十六进制输出:
void Client::SendDiagnosticData() { std::string buf; std::string buf2; DiagnosticData dData = GenerateDiagnosticData(); DiagnosticData dData2; // 序列化 if (!dData.SerializeToString(&buf)) { qDebug() << "序列化失败"; return; } // 反序列化:直接传递std::string,避免空字节截断 if (!dData2.ParseFromString(buf)) { qDebug() << "反序列化失败"; return; } // 二次序列化 if (!dData2.SerializeToString(&buf2)) { qDebug() << "二次序列化失败"; return; } // 对比长度与内容 qDebug() << "原序列化长度:" << buf.size(); qDebug() << "二次序列化长度:" << buf2.size(); qDebug() << "内容是否一致:" << (buf == buf2); // 二进制转十六进制输出真实内容 auto toHexString = [](const std::string& s) { QString hexStr; for (unsigned char c : s) { hexStr += QString("%1 ").arg(c, 2, 16, QChar('0')); } return hexStr.trimmed(); }; qDebug() << "原序列化十六进制:" << toHexString(buf); qDebug() << "二次序列化十六进制:" << toHexString(buf2); }
3. 关于float类型字段的说明
当velocity为float类型时,序列化结果是二进制浮点数据,包含不可打印控制字符,qDebug输出的转义符是正常现象,并非序列化失败。通过十六进制输出可以查看完整的序列化内容。
内容的提问来源于stack exchange,提问作者Merab
相关产品推荐
相关产品推荐

