c++ - 当对字段使用不同的值时,Protobuf 序列化长度不同

标签 c++ serialization go protocol-buffers

我的 Protobuf 消息由 3 个 double 组成

syntax = "proto3";

message TestMessage{
  double input = 1;
  double output = 2;
  double info = 3;
}

当我将这些值设置为

test.set_input(2.3456);
test.set_output(5.4321);
test.set_info(5.0);

序列化的消息看起来像

00000000  09 16 fb cb ee c9 c3 02  40 11 0a 68 22 6c 78 ba  |........@..h"lx.|
00000010  15 40 19                                          |.@.|
00000013

当使用 test.serializeToArray 并且无法通过使用相同 protobuf 消息的 go 程序成功反序列化时。当试图从 C++ 程序中读取它时,我得到了一个 0 作为信息,因此消息似乎已损坏。

当使用 test.serializeToOstream 时,我得到了这个消息,go 和 c++ 程序都可以成功反序列化它。

00000000  09 16 fb cb ee c9 c3 02  40 11 0a 68 22 6c 78 ba  |........@..h"lx.|
00000010  15 40 19 00 00 00 00 00  00 14 40               |.@........@|
0000001b

将值设置为

test.set_input(2.3456);
test.set_output(5.4321);
test.set_info(5.5678);

test.serializeToArraytest.serializeToOstream 生成的序列化消息看起来像

00000000  09 16 fb cb ee c9 c3 02  40 11 0a 68 22 6c 78 ba  |........@..h"lx.|
00000010  15 40 19 da ac fa 5c 6d  45 16 40                 |.@....\mE.@|
0000001b

并且可以被我的 go 和 cpp 程序成功读取。

我在这里错过了什么?为什么 serializeToArray 在第一种情况下不起作用?

编辑: 事实证明,serializeToString 也能正常工作。

这里是我用来比较的代码:

file_a.open(FILEPATH_A);
file_b.open(FILEPATH_B);

test.set_input(2.3456);
test.set_output(5.4321);
test.set_info(5.0);

//serializeToArray
int size = test.ByteSize();
char *buffer = (char*) malloc(size);
test.SerializeToArray(buffer, size);
file_a << buffer;

//serializeToString
std::string buf;
test.SerializeToString(&buf);
file_b << buf;

file_a.close();
file_b.close();

为什么 serializeToArray 没有按预期工作?

编辑2:

当使用 file_b << buf.data() 而不是 file_b << buf.data() 时,数据也会损坏,但为什么呢?

最佳答案

我认为您犯的错误是将二进制视为字符数据并使用字符数据 API。许多 API 在第一个零字节 (0) 处停止,但这是 protobuf 二进制文件中完全有效的值。

您需要确保基本上不使用任何此类 API - 纯粹使用二进制安全 API。

因为您指出 size 是 27,所以这一切都合适。

基本上,5.0 的二进制表示包括 0 个字节,但您很容易及时发现其他值的相同问题。

关于c++ - 当对字段使用不同的值时,Protobuf 序列化长度不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44806362/

相关文章:

C++哈希算法

c++ - Qt 中进程的有趣任务

java - 保存 Jackson ObjectMapper 的配置

与实体管理器多次合并后,Symfony/Doctrine实体会导致脏实体关联

c# - 数据访问库返回数据集或对象

logging - 我应该在我的 Go 网络抓取工具中的什么地方添加日志记录?

go - 访问类型声明父方法

c++ - 标记化并转换为 pig latin

Emacs 的 C++11 模式或设置?

mysql - 来自 Google CloudSQL 的错误 HTTP 响应