一、cJson介绍
首先对于json最好的解释(含图解):https://www.json.org/json-en.html
cJson的源代码链接(github):https://github.com/DaveGamble/cJSON
别看项目文件那么多,其实核心代码都在下图两个文件中
cJson项目介绍(大致从README.md翻译而来):
cJSON旨在成为您可以完成工作的最愚蠢的解析器。它是C的单个文件,也是单个头文件。
总体代码量才1000行左右,相对来说还是非常容易去理解。
二、使用方式
使用教程:https://blog.csdn.net/weixin_42887343/article/details/114318670
三、源码分析
1、宏定义
首先使用宏定义了json文中对象的数据类型,如下所示
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Int 3
#define cJSON_Double 4
#define cJSON_String 5
#define cJSON_Array 6
#define cJSON_Object 7
#define cJSON_IsReference 256
定义的上述宏用于cJSON结构体类型的分类。所以后文中,不管说的对象、数组、还是节点,其实都是cJSON结构体的实例化,只是不同定义的类型和用处不一样,称呼所以也不一样而已。
json文件结构内容如上图所示,框1是一个cJSON_Object类型,框2是cJSON_String类型,框3是cJSON_Array类型。
在程序中对该json文件结构的描述,就是使用n个实例化的cJSON结构体表示,每个节点就是一个实例化的cJSON结构体。
2、结构体
cJson中 最重要 的结构体如下所示,cJSON中json数据采用双向链表来存储。
/* 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 */
uint64 valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
int sign; /* sign of valueint, 1(unsigned), -1(signed) */
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;
(1)cJSON *next, *prev;
定义的双向链表指针。
(2)cJSON *child
定义的子对象指针。
(3)int type;
定义的该对象的类型,具体类型上面宏定义已经说明。
(4)对象数据存储,由于对象数据类型不确定,所以包含多个数据类型,如下:
char *valuestring; /* The item's string, if type==cJSON_String */
uint64 valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
int sign; /* sign of valueint, 1(unsigned), -1(signed) */
注释说明了,不同类型时候,不同的变量有效。
(5)char *string
该对象的对象名,和4组合在一起构成 “键值对” 。
3、函数
cJSON操作JSON对象实质就是操作链表的过程。本次分析cJSON添加对象和删除对象的操作。
- json文件解析:------------------------------------------------------------------------------------------------------
json文件解析成cJSON结构体实体,将整个json文件内容转为代码中的实例化的结构体内容。
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
- json文件输出:------------------------------------------------------------------------------------------------------
和json文件解析相反,下面函数是将代码中的实例化的结构体内容,转为json文件保存。
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(cJSON *item);
- 删除所有实例化的cJson结构体对象:---------------------------------------------------------------------
在前面的cJSON_Parse函数中,创建cJSON结构体对象时申请了内存,所以必定由内存释放的函数。从下面代码看出,只要传入根对象(root),其之下的所有子对象都将被删除。
/* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)
{
cJSON *next;
while (c)
{
next = c->next;
if (!(c->type & cJSON_IsReference) && c->child)
cJSON_Delete(c->child);
if (!(c->type & cJSON_IsReference) && c->valuestring)
cJSON_free(c->valuestring);
if (c->string)
cJSON_free(c->string);
cJSON_free(c);
c = next;
}
}
- 创建对象操作:------------------------------------------------------------------------------------------------------
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull();
extern cJSON *cJSON_CreateTrue();
extern cJSON *cJSON_CreateFalse();
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateDouble(double num, int sign);
extern cJSON *cJSON_CreateInt(uint64 num, int sign);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray();
extern cJSON *cJSON_CreateObject();
其实上述函数的实现基本差不多,只是cJSON结构体的type成员赋值不一样,用于对象的区分,如下源代码实现就可看出,只有 item->type
赋值存在区别。
cJSON *cJSON_CreateArray()
{
cJSON *item = cJSON_New_Item();
if (item)
item->type = cJSON_Array;
return item;
}
cJSON *cJSON_CreateObject()
{
cJSON *item = cJSON_New_Item();
if (item)
item->type = cJSON_Object;
return item;
}
- 创建数组操作:------------------------------------------------------------------------------------------------------
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(int *numbers, int sign, int count);
extern cJSON *cJSON_CreateFloatArray(float *numbers, int count);
extern cJSON *cJSON_CreateDoubleArray(double *numbers, int count);
extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
看源代码,函数返回的都是第一个对象的地址,即数组首地址。
- 对象删除操作:------------------------------------------------------------------------------------------------------
/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
extern void cJSON_DeleteItemFromArray(cJSON *array, int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string);
- 对象修改操作:------------------------------------------------------------------------------------------------------
/* Update array items. */
extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object, const char *string,
cJSON *newitem);