[✔️]lua-cjson 编译,在unity中使用cjson

409 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 23 天,点击查看活动详情

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进行编译:

  1. vscode打开c-json
  2. vscode安装好cmake相关的插件
  3. vscode中输入命令(Ctrl+P): cmake:configure,会自动生成build目录
  4. 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,因为时间问题,我就不再进行验证了。