cJSON源码解析

cJSON源码解析

程序结构

这是一个十分轻量级的C语言代码结构,只有一个头文件cJSON.h,一个源文件cJSON.c和一个测试文件。它的作用是将无序的,杂乱的字符码解析成有顺序、有格式的代码行文件(JSON格式),便于查看。

解析顺序

  1. 测试文件
  2. 定义文件;
  3. 头文件;

测试文件

看主程序

int main (int argc, const char * argv[]) {
	/* a bunch of json: */
	char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\":       \"rect\", \n\"width\":      1920, \n\"height\":     1080, \n\"interlace\":  false,\"frame rate\": 24\n}\n}";	
	char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
	char text3[]="[\n    [0, -1, 0],\n    [1, 0, 0],\n    [0, 0, 1]\n	]\n";
	char text4[]="{\n		\"Image\": {\n			\"Width\":  800,\n			\"Height\": 600,\n			\"Title\":  \"View from 15th Floor\",\n			\"Thumbnail\": {\n				\"Url\":    \"http:/*www.example.com/image/481989943\",\n				\"Height\": 125,\n				\"Width\":  \"100\"\n			},\n			\"IDs\": [116, 943, 234, 38793]\n		}\n	}";
	char text5[]="[\n	 {\n	 \"precision\": \"zip\",\n	 \"Latitude\":  37.7668,\n	 \"Longitude\": -122.3959,\n	 \"Address\":   \"\",\n	 \"City\":      \"SAN FRANCISCO\",\n	 \"State\":     \"CA\",\n	 \"Zip\":       \"94107\",\n	 \"Country\":   \"US\"\n	 },\n	 {\n	 \"precision\": \"zip\",\n	 \"Latitude\":  37.371991,\n	 \"Longitude\": -122.026020,\n	 \"Address\":   \"\",\n	 \"City\":      \"SUNNYVALE\",\n	 \"State\":     \"CA\",\n	 \"Zip\":       \"94085\",\n	 \"Country\":   \"US\"\n	 }\n	 ]";
	char text6[]="[\n   int main() \n { \n int a=2;\n int b =3;\n int c=a+b;\n } ]";
	/* Process each json textblock by parsing, then rebuilding: */
	doit(text1);
	doit(text2);	
	doit(text3);
	doit(text4);
	doit(text5);
	doit(text6);
	/* Now some samplecode for building objects concisely: */
	create_objects();
	
	return 0;
}

主程序声明了6个含有不同内容的字符数组,该程序的测试目的就是将这6组字符乱码(直接printf肯定是乱码),解析成代码行格式的文件。
可以直接看出来,doit(textn)便是解析函数。

查看测试程序中的doit函数,如下

void doit(char *text)
{
	char *out;
	cJSON *json;
	
	json=cJSON_Parse(text);
	if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());}
	else
	{
		out=cJSON_Print(json);
		cJSON_Delete(json);
		printf("%s\n",out);
		free(out);
	}
}

可以看出,doit所需的参数即使在主程序中声明的text字符数组。
doit中分别创建了一个输出指针*out,一个自定义类型对象cJSON json;而json中存放的内容就是解析后的文本格式数据。(见头文件解释)。cJSON_Parse(text)解析完毕的内容存入json中(见定义文件解释)

定义文件cJSON.c

cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}

cJSON_Print(json)函数只有这些,显然这个实例的特点就是运用了大量的指针,内存管理和函数嵌套等方法,这样的好处是能缩减代码量级,业务逻辑也更加清楚。我们再去看cJSON_ParseWithOpts(value,0,0)对应的内容

cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{
	const char *end=0;
	cJSON *c=cJSON_New_Item();//new 一个cJSON对象*c
	ep=0;//一开始声明的指针 
	if (!c) return 0;       /* memory fail */	//内存故障,空 

	end=parse_value(c,skip(value));
	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */

	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
	if (return_parse_end) *return_parse_end=end;
	return c;
}

头文件cJSON.h

自定义类型cJSON一定是放在头文件中

typedef struct cJSON {
	struct cJSON *next,*prev;	/* next/prev两个结构体指针可以在数组/对象链表中移动,可以使用GetArraySize/GetArrayItem/GetObjectItem等方法;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声明了类型多变,存储内容也不固定的结构体,这便于存放解析出来的多种类型数据。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倪华川

赏杯可乐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值