KEEP K.I.S.S.

tk's blog

protobuf 跨语言使用字符串编码问题

    好久没更新了..... 这段时间,咳

    最近公司项目组有个需求,就是用C++写一个可供 Android 和 WinCE 的跨平台语言底层调用,从下层向上层传递数据。背景是之前项目是在 WinCE 上做的,开发语言是 C#, 现在在开发 Android 的版本,所以想把底层涉密的底层算法用 C++ 重做,同时反馈给之前的 CE 版本。

    跨语言调用传递数据主要就是一个协议,因为不管传递什么数据,底层来说都是一丢丢的字节流,这里只要能从字节流中解析出一致的数据就可以。这里准备采用 google 的 protobuf。

    官方的 protobuf 默认支持三种语言,C++/Java/Python,支持 C# 的有社区版本,protobuf-csharp-port 。

    今天就测试了下从 C++ 传递数据到 C# 中解析的情况,这里暂时没有考虑跨语言直接调用,而是用 C++ 版本 序列化一个文件然后让 C# 版本解析。这之中,如果 .protoc 文件string 定义的字段都是使用 ASCII 编码的话,是没有什么问题的。如果用到中文,这里到 C# 里就会乱码,很常见的编码问题 Orz。主要问题还是 VS 的 C++ 文件编码,因为 VS 默认是 本地编码(中文的就是 GBK),所以里面字符串字面量也是本地编码,如果你把文件编码转换为  UTF-8 无 BOM,会无法编译,如果转换为 UTF-8 带 BOM 格式,VS 编译过程中会把UTF-8带BOM格式文件转换为本地编码.....蛋疼。所以在 C++ 版本里用了一个 GBK 转 UTF-8 的函数,把 GBK 编码的 string 转为 UTF-8 编码的 string,然后序列化。再到 C# 中解析就正常了。如果在 C++版本中不转换而在 C# 中转换编码的话,我找了但是貌似没找到可行的方法。

    无力吐槽 VS 的文件编码处理了。统一向 UTF-8 靠拢才是良策。PS: 貌似 C# 默认写入文件编码就是 UTF-8(待确认)。

    UTF-8 编码避免了字节序(大小端)问题,适合通信。 UTF-16 就很适合本地使用。

    顺便吐槽一下 ParseFromArray 这个 API ,第二个参数必须正好是数组里存放的 message 的 ByteSize 大小,大一点也不行, 所以不能传递数组的大小。原因。所以最好在序列化之前写入 ByteSize 大小用以标识。