You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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类型后,仍存在部分字段内容缺失的情况。

问题根源

  1. 字段Setter调用错误:Protobuf会将proto文件中的驼峰命名字段自动转为C++代码中的蛇形命名(下划线分隔小写),你调用了错误的Setter方法,导致transportWeight和tirePresure字段未被正确赋值,序列化时这两个字段未被写入。
  2. ParseFromString参数错误:传递buf->c_str()作为反序列化输入,而Protobuf序列化内容为二进制,可能包含空字节,c_str()会在第一个空字节处截断数据,导致反序列化不完整。
  3. 二进制内容输出误解: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 15:26:32