【大一C语言项目】Cjson的认识与实现(二)

本文详细介绍了C语言实现的JSON解析库Cjson的使用方法,包括序列化、反序列化过程,以及Cjson.h头文件中的关键数据结构和函数。通过Cjson,可以方便地在C程序中处理JSON数据,进行对象和数组的增删改查操作。同时,文章还提供了Cjson库中结构体的源码分析,帮助理解其实现原理。
摘要由CSDN通过智能技术生成

【大一C语言项目】Cjson的认识与实现(二)

参考资料:
哔哩哔哩CJson开源库使用及注意事项
CJson开源项目下载地址
cJSON源码刨析

一、使用Cjson库

下载CJSON:CJson开源项目下载地址
我们解压后看到cJSON.h和cJSON.c两个文件,我们把这两个文件加入到项目中
在这里插入图片描述
在这里插入图片描述
序列化

序列化:把对象转化为可传输的字节序列过程称为序列化。
反序列化:把字节序列还原为对象的过程称为反序列化。

cJSON要实现的主要是是反序列化的过程,在c语言程序中利用相关库函数调用将字节序列还原成对象并打印输出的过程

二、Cjson.h文件源码分析

源码

/*
  Copyright (c) 2009 Dave Gamble

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

#ifndef cJSON__h
#define cJSON__h

#ifdef __cplusplus
extern "C"
{
#endif

/* cJSON Types:*/ 
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6

#define cJSON_IsReference 256
#define cJSON_StringIsConst 512

/* 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;

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

/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);


/* 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);
/* 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);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
/* Delete a cJSON entity and all subentities. */
extern void   cJSON_Delete(cJSON *c);

/* Returns the number of items in an array (or object). */
extern int	  cJSON_GetArraySize(cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);

/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);

/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);

/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);

/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
extern void	cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);	/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);

/* 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_InsertItemInArray(cJSON *array,int which,cJSON *newitem);	/* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);

/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */

/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);

extern void cJSON_Minify(char *json);

/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))

/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#define cJSON_SetNumberValue(object,val)		((object)?(object)->valueint=(object)->valuedouble=(val):(val))

#ifdef __cplusplus
}
#endif

#endif

逐段分析与翻译

预处理

#ifndef cJSON__h
#define cJSON__h//定义cJSON__h头文件

#ifdef __cplusplus//extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码
extern "C"
{
#endif

cJSON数据类型

/* cJSON Types:*/ 
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6

#define cJSON_IsReference 256//暂时不知道是干嘛的
#define cJSON_StringIsConst 512//字符串大小常量?

/*使用结构体cJSON结构体表示键值对*/
typedef struct cJSON {
	//双向链表来实现
	struct cJSON *next,*prev;//数组/对象链,next和prev应该是同一级的
	struct cJSON *child;//用来实现对象/数组嵌套	
	int type;//数据类型					
	char *valuestring;//值为字符串类型			
	int valueint;//值为整型			
	double valuedouble;	//值为浮点数类型		
	char *string;//键名,区分valuestring				
} cJSON;

参考这位大佬的博客
在这里插入图片描述
内存操作

typedef struct cJSON_Hooks {
      void *(*malloc_fn)(size_t sz);//这两个内存相关操作细节不是很清楚
      void (*free_fn)(void *ptr);
} cJSON_Hooks;

/* 让cJSON数据类型能够支持 malloc, realloc and free 这些操作 */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);//extern void 函数外部声明,使得可以多文件调用

size_t相关知识点
size_t和unsigned int有所不同,size_t的取值range是目标平台下最大可能的数组尺寸,貌似可以增加不同平台的可移植性

基本操作函数声明

cJSON整体操作,查询,打印,删除

/* 提供一个JSON块,然后返回一个你可以查询的cJSON对象。完成后调用cJSON_Delete. 应该是解析用的,把json数据打包成cJSON格式*/
extern cJSON *cJSON_Parse(const char *value);
/* 将一个cJSON实体渲染解析成文本打印出来,并且在完成的时候释放char* */
extern char  *cJSON_Print(cJSON *item);
/* 将一个cJSON实体渲染解析成文本没有格式的打印出来,并且完成的时候释放char* */
extern char  *cJSON_PrintUnformatted(cJSON *item);
/* 使用缓冲策略将一个cJSON实体渲染成文本,prebuffer是对最终大小的猜测,猜得好可以减少重新分配. fmt=0 表示无格式 unformatted, fmt=1 表示有格式 formatted */
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
/* 删除一个cJSON实体和他所有子实体 */
extern void   cJSON_Delete(cJSON *c);

对象/数组获取信息

/* 返回对象/数组大小. */
extern int	  cJSON_GetArraySize(cJSON *array);
/* 从数组中获取元素,如果不成功返回NULL */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* 从对象中获取string,不区分大小写 */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);

报错

/* 报错,用于分析失败的解析。这将返回一个指向解析错误的指针。你可能需要回溯几个字符来理解它,当cJSON_Parse()成功时返回0。*/
extern const char *cJSON_GetErrorPtr(void);

创建

/* cJSON数据类型创建 */
extern cJSON *cJSON_CreateNull(void);//申请一个空的cJSON数据结构内存空间,然后将其成员type置为cJSON_NULL类型。
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);//采用const char * string
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);
/* 创建计数数组 */
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);

添加item

/* 添加item到指定数组或对象 */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
extern void	cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);	/* 当字符串绝对是const(即一个字面意思,或好比),并且一定会在cJSON对象中存在时,使用这个。 */

删除item

/* 从指定数组或对象中删除元素*/
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);

更新替换插入item

/* 更新数组元素. */
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem);	/* 原有数组右移 */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);/* 替换数组指定位置元素 */
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);/* 替换对象指定名字元素 */

cJSON复制粘贴

/* 复制一个cJSON*/
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* 复制将在新的内存中创建一个新的、与你传递的cJSON项目相同的项目,该项目将在需要被释放。当recurse!=0时,它将复制任何连接到项目的子项目。item->next和->prev指针在从Duplicate返回时始终为零。 */

/*ParseWithOpts允许你请求(并检查)JSON是null terminated,并检索到解析的最后一个字节的指针。 */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);

暂时不清楚的

extern void cJSON_Minify(char *json);

宏来快速创建

#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
/*  当分配一个整数值时,也需要将其传给valuedouble. */
#define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#define cJSON_SetNumberValue(object,val)		((object)?(object)->valueint=(object)->valuedouble=(val):(val))

小结

  1. 多文件编译我们可以创建一个头文件把所有函数都用extern声明,方便调用,而且很清晰。很适合一堆函数的情况
  2. cJSON处理重点在于对象和数组类型数据的处理各种增删改查以及扩展操作
  3. 可以使用宏来简化语法
  4. JSON数据格式可以自定义一个结构体使用双向链表来实现。
    为何使用双向链表?数组,单向链表,双向链表区别
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值