SimpleJson解析太慢
因为项目中需要解析json,使用的是SimpleJson,不过发现当json比较大的时候,SimpleJson的性能不是太好,于是在寻找替代品,因为其他项目中使用的是lua-json,经历过项目的验证,所以就顺藤摸瓜,找到了lua-cjson官网,对应的lua-cjson-github。
lua-cjosn
根据lua-cjson的描述,解析json使用的是c-json,反正都是c++,最终要在unity中使用,都需要通过dll的方式调用。
第一步就是要编译c-json,因为c-json是使用CMake,我们只需要安装CMake进行编译
cmkae -B ./build cd build cmake ../ make
如果你感觉敲命令行太麻烦,可以选择使用vscode进行编译:
- vscode打开c-json
- vscode安装好cmake相关的插件
- vscode中输入命令(Ctrl+P):
cmake:configure
,会自动生成build目录
- vscode中输入命令(Ctrl+P):
cmake:build
,最终就在build/Debug目录下生成相关的dll
以上整个过程在vscode中的体验还是非丝滑的,推荐推荐。
dll的位数问题
unity编辑器如果是64位的,那么导入的dll也需要是64的,怎么生成64位的dll呢?
其实只需要切换下cmake的编译器,选择64位的编译器,生成的最终dll就是64位的。
unity好像不允许64位和32位的dll共存。
unity中调用dll函数
导入dll到unity
将dll放到Asset/Plugins
即可,次级目录不限,
在C#中声明dll的函数
- c++的函数声明
CJSON_PUBLIC(const char*) cJSON_Version(void);
- c#的函数声明
[DllImport ("cjson")] // cjson是导入的dll名字,不用关心目录问题,换而言之,dll是不允许重名的 private static extern /*前半部分是固定的格式*/ IntPtr cJSON_Version();
我们在编写c#函数声明时,需要关心下参数和返回值,凡是c语言指针类型的,到c#中统一都是IntPtr
,如果你对指针理解的非常到位,其实指针就是一个int类型的内存地址数据。
其他的基础类型,int、double、float都可以直接照搬,没有类型转换。
c#调用函数参数的类型转换
c语言函数参数类型为const char*
,对应的c#类型为IntPtr
。
所以在c#中调用该函数时,我们需要将c#的string转换为IntPtr。
string str = "string"; IntPtr ptr = Marshal.StringToHGlobalAnsi(str);
具体原理,仔细体会下就大致能想明白了,稍微绕了个弯弯。
c语言的结构体在c#中解析
[StructLayout(LayoutKind.Sequential)] public struct _CJson { public IntPtr next; public IntPtr prev; public IntPtr child; public int type; public IntPtr valueString; public int valueint; public double valuedouble; public IntPtr str; } IntPtr ptr; _CJson jsonObj = (_CJson)Marshal.PtrToStructure(ptr, typeof(_CJson));
这里主要用到了StructLayout
,在编写时注意内存布局的问题,我实践过程中发现有些值解析不出来。
比如这里的str
是正确的,但是valuedouble
始终为0,在c语言的测试例中是可以正常读取到number的值的,最后放弃了,改用其他api(cJSON_GetNumberValue)获取值。
可能是我内存布局写的有问题,这里我就不再深究了。
json解析其他的选择
后来同事反馈,rapidjson性能更加强劲,吊打cjson,因为时间问题,我就不再进行验证了。