NanoPB编码重复int32值后C#解码数值翻倍问题排查
问题:Protobuf编码int数组经MQTT发送后,C#端解码数值翻倍
将int数组编码为Protobuf消息后通过MQTT发送至C#应用,解码时出现异常:C#端得到的所有int32数值均翻倍,但把相同字节数据回传给NanoPB应用解码时,数值显示正常。
相关文件及输出
Proto定义文件
syntax = "proto2"; message stringCallback{ required string name = 1; required string surname = 2; required int32 age = 3; repeated int32 values = 4; }
NanoPB编码函数
bool IntArray_encode(pb_ostream_t *ostream, const pb_field_t *field, void* const* arg){ IntArray* arr = (IntArray*)*arg; for(int i = 0; i < arr->count; i++){ if(!pb_encode_tag_for_field(ostream, field)){ Serial.println("Encoding failed!"); return false; } if(!pb_encode_svarint(ostream, arr->values[i])){ Serial.println("Encoding failed!"); return false; } } return true; }
NanoPB解码函数
bool IntArray_decode(pb_istream_t *stream, const pb_field_t *field, void** arg){ IntArray* arr = (IntArray*)*arg; int64_t number; if(!pb_decode_svarint(stream, &number)){ Serial.println("Decoding failed!"); return false; } Serial.println(number); IntArray_add(arr, (int32_t)number); return true; }
NanoPB解码输出
Name = Testing Surname = Purpose Age = 23 [14 11 10 5 109 32321 23 19 15]
C#解码输出
Name = Testing Surname = Purpose Age = 23 [28 22 20 10 218 64642 46 38 30 ]
问题原因
Proto文件中values字段定义为标准int32类型,但NanoPB编码时使用了pb_encode_svarint函数——该函数是针对sint32/sint64类型设计的,会对数值执行ZigZag编码。而C#端的Protobuf库会按照标准int32的规则解码(不处理ZigZag),正数的ZigZag编码结果恰好是原数值的2倍,因此出现了数值翻倍的异常。
解决方案
有两种修复方式:
- 修改编码逻辑:将NanoPB编码中的
pb_encode_svarint替换为pb_encode_varint,标准int32在Protobuf中使用varint编码(无ZigZag):if(!pb_encode_varint(ostream, arr->values[i])){ Serial.println("Encoding failed!"); return false; } - 统一字段类型:将Proto文件中的
values字段类型改为sint32,这样两端都会采用ZigZag编解码规则,结果即可统一:repeated sint32 values = 4;
内容的提问来源于stack exchange,提问作者J.Meulenbeld
相关产品推荐
相关产品推荐

