cJSON源码分析

因为最近在和ONENET云平台数据通信相关的项目中遇到对JSON数据的处理,于是对cJSON进行了深入研究,感觉收益匪浅,如沐春风,当然个人觉得代码格式阅读起来不是特别方便。前人种树,后人乘凉,希望整理的内容可以给道友门学习cJSON的时候提供绵薄之力,当然不足之处请各位道友批评指正,下面是我在学习过程中的相关资料。

一、JSON

先对JSON的数据格式做一个简要的介绍。

1、定义

百度百科对JSON的定义是:JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。

2、JSON语法规则

  • 数据在名称/值对中
  • 数据由括号分隔
  • 大括号保存对象
  • 中括号保存数组

3、JSON值

JSON 值可以是:

  • 数字(整数或浮点数)
{ "age":30 }
  • 字符串(在双引号中)
{"name" : “brook”}
  • 逻辑值(true 或 false)
{ “flag” : true }

 

  • 对象(在大括号中)
对象可以包含多个 key/value(键/值)对。
{ "name”:"brook" , “age”:24 }
  • 数组(在中括号中)
数组可包含多个对象:
{
"sites": [
{ "name":"菜鸟教程" , "url":"www.runoob.com" }, 
{ "name":"google" , "url":"www.google.com" }, 
{ "name":"微博" , "url":"www.weibo.com" }
]
}
在上面的例子中,对象 "sites" 是包含三个对象的数组。每个对象代表一条关于某个网站(name、url)的记录。
  • null
{ "runoob":null }

二、cJSON结构体

言归正传,回到cJSON,cJSON是C语言中的一个JSON编解码器,在一些面向对象的编程语言(例如C++,Java,Python)中,存在字符串数组、字典等数据结构,可以非常方便地对JSON数据进行处理,而C语言中只能使用结构体来处理JSON数据,学习使用cJSON把cJSON结构体作为切入点是正确的选择。cJSON结构体如下所示:

/* The cJSON structure: */
typedef struct cJSON {
	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */

	int type;					/* The type of the item, as above. */

	char *valuestring;			/* The item's string, if type==cJSON_String */
	int valueint;				/* The item's number, if type==cJSON_Number */
	double valuedouble;			/* The item's number, if type==cJSON_Number */

	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;

从上面的cJSON结构体可以看出,cJSON数据结构为多级双向链表(初步猜测,才疏学浅,不喜勿喷)。结构体由数据指针、数据项类型、数据和节点名称4部分组成。

  • 数据指针:包括指向双向链表前驱和后继的指针prev和next,指向孩子节点的child指针。
  • 数据项类型:有七种数据项类型,False,True,NULL,数字,字符串,数组,对象。
  • 数据:这里需要注意的是,当数据项类型为数字时,数据将在valueint和valuedouble中同时保存。
  • 节点名称可能为空

光说不练假把式,先拿第一部分的数组举个栗子,个人觉得最终在内存中形成的结构应该如下所示(没有好的画图工具,用了visio,xx画质,请各位见谅):

个人做了以下总结:

  • 遇到大括号或中括号,如果没有形成键值对关系的,一般节点名称为空。
  • 逗号分隔的为属于同一层的节点,存在前驱和后继的关系。
  • 分级的层次关系通过child指针表示。

三、内存管理

1、内存管理结构体

cJSON使用Hooks进行内存管理,Hooks结构体有内存分配和内存释放函数组成,如下所示:

typedef struct cJSON_Hooks {
      void *(*malloc_fn)(size_t sz);
      void (*free_fn)(void *ptr);
} cJSON_Hooks;

通过Hooks初始化函数可以看出,如果hooks没有自定义的内存分配和释放函数,默认使用malloc和free函数。

static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;

void cJSON_InitHooks(cJSON_Hooks* hooks)
{
    if (!hooks) { /* Reset hooks */
        cJSON_malloc = malloc;
        cJSON_free = free;
        return;
    }

	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free;
}

2、创建节点

创建节点过程很简单,先进行内存分配,然后将内存清0,即数据存储区域为空,指针域指向NULL。

/* Internal constructor. */
static cJSON *cJSON_New_Item(void)
{
	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
	if (node) memset(node,0,sizeof(cJSON));
	return node;
}

通过调用cJSON_New_Item创建基本类型的节点,都是先调用cJSON_New_Item,然后将类型变量设置为相应类型,还有一部分给数据单元赋值(比如bool、number、string类型):

/* Create basic types: */
cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}

通过调用cJSON_CreateArray创建4种基本类型的数组,用于批量创建节点:

/* Create Arrays: */
cJSON *cJSON_CreateIntArray(const int *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray(
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值