cJSON解析和打包

1. JSON格式

JSON格式
C语言:json库的使用
cJSON库源代码获取:https://github.com/DaveGamble/cJSON.git
也可以从我的GitHub获取,包含了解析的打包的两个测试程序。

2. 解析

主要过程分为三步:
使用cJSON_Parse将字符串转换为cJSON结构。
使用cJSON_GetObjectItem获取指定键对应的值。
使用cJSON_Delete销毁创建的cJSON结构。
当涉及数组时,需要多使用两个函数:

int    cJSON_GetArraySize(cJSON *array);
cJSON* cJSON_GetArrayItem(cJSON *array,int item);

使用cJSON解析JSON字符串

3. 打包

cJSON库的安装与使用

注意事项:主要是内存回收。
cJSON打包功能使用-代码案例、特别注意事项

4. 源码分析

cJSON源码分析

在test.c程序中,我们解析的是JSON如下:

char *Output2 = "{\"state\":1}";

对应到cJSON.c文件中的函数,重点看两个函数:

/* Parser core - when encountering text, process appropriately. */
static const char *parse_value(cJSON *item,const char *value)
{
	if (!value)						return 0;	/* Fail on null. */
	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; }
	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; }
	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; }
	if (*value=='\"')				{ return parse_string(item,value); }
	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); }
	if (*value=='[')				{ return parse_array(item,value); }
	if (*value=='{')				{ return parse_object(item,value); }

	ep=value;return 0;	/* failure. */
}

在此函数中,可以看到根据第一个字符进入不同分支。我们主要看parse_object函数:

/* Build an object from the text. */
static const char *parse_object(cJSON *item,const char *value)
{
	cJSON *child;
	if (*value!='{')	{ep=value;return 0;}	/* not an object! */
	
	item->type=cJSON_Object;
	value=skip(value+1);
	if (*value=='}') return value+1;	/* empty array. */
	
	item->child=child=cJSON_New_Item();
	if (!item->child) return 0;
	value=skip(parse_string(child,skip(value)));
	if (!value) return 0;
	child->string=child->valuestring;child->valuestring=0;
	if (*value!=':') {ep=value;return 0;}	/* fail! */
	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
	if (!value) return 0;
	
	while (*value==',')
	{
		cJSON *new_item;
		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */
		child->next=new_item;new_item->prev=child;child=new_item;
		value=skip(parse_string(child,skip(value+1)));
		if (!value) return 0;
		child->string=child->valuestring;child->valuestring=0;
		if (*value!=':') {ep=value;return 0;}	/* fail! */
		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */
		if (!value) return 0;
	}
	
	if (*value=='}') return value+1;	/* end of array */
	ep=value;return 0;	/* malformed. */
}

尤其要注意链表的指向。在此函数之前,先创建了一个空的cJSON结构体,作为起始节点。其child指向的结构体才开始存储信息:

valueint = 1
string = state

5. 问题记录

  1. date值是什么形式

  2. 打印输出后,换行符

  3. 小数点精度控制
    在这里插入图片描述
    程序中调用如下:

value = cJSON_CreateNumber(120.8);

输出变为120.800000。查看sJSON.c文件,cJSON_CreateNumber函数定义如下:

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;}

在函数内部增加

printtf("%f",num)

发现num已经变为120.800000
如果把形参改为float,型,打印后为120.800003
未解决,保留。
临时解决办法为固定小数点后两位,需要修改sJSON.c文件中的print_number函数

static char *print_number(cJSON *item,printbuffer *p)
{
	char *str=0;
	double d=item->valuedouble;
	if (d==0)
	{
		if (p)	str=ensure(p,2);
		else	str=(char*)cJSON_malloc(2);	/* special case for 0. */
		if (str) strcpy(str,"0");
	}
	else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
	{
		if (p)	str=ensure(p,21);
		else	str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */
		if (str)	sprintf(str,"%d",item->valueint);
	}
	else
	{
		if (p)	str=ensure(p,64);
		else	str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */
		if (str)
		{
			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d);
			else												sprintf(str,"%f",d);
		}
	}
	return str;
}

将最后一个sprintf修改为sprintf(str,"%.2lf",d);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值