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

Protobuf serialization length differs when using different values for field

我的 Protobuf 消息由 3 个双打组成

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 时,go 程序无法使用相同的 protobuf 消息成功反序列化。当试图从 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 个字节,但您很容易及时发现其他值的相同问题。