CJson源码解析之创建不同类型的键值对
@TOC
前言
在现代编程中,JSON已经成为了一种非常流行的数据交换格式。它的简洁性和易读性使得开发者可以轻松地在不同的系统和应用之间共享和理解数据。CJson是一个轻量级的JSON解析库,它提供了一种简单和高效的方式来解析和生成JSON数据。本文将深入探讨CJson的源码,特别是它如何创建不同类型的键值对。
这段代码比较简单,这里简单略过
cJSON_CreateNull
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_NULL;
}
return item;
}
在这个函数中,首先调用cJSON_New_Item
函数来分配一个新的cJSON对象。如果内存分配成功,那么就将这个新对象的类型设置为cJSON_NULL
,表示这个对象代表一个JSON null值。
cJSON_CreateTrue
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_True;
}
return item;
}
这个函数的实现与cJSON_CreateNull
非常相似,唯一的区别是它将新对象的类型设置为cJSON_True
,表示这个对象代表一个JSON true值。
cJSON_CreateFalse
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_False;
}
return item;
}
这个函数的实现也与cJSON_CreateNull
非常相似,唯一的区别是它将新对象的类型设置为cJSON_False
,表示这个对象代表一个JSON false值。
cJSON_CreateBool
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = boolean ? cJSON_True : cJSON_False;
}
return item;
}
这个函数首先调用cJSON_New_Item
函数来分配一个新的cJSON对象。然后,根据传入的布尔值参数,将新对象的类型设置为cJSON_True
或cJSON_False
。
cJSON_CreateNumber
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_Number;
item->valuedouble = num;
/* use saturation in case of overflow */
if (num >= INT_MAX)
{
item->valueint = INT_MAX;
}
else if (num <= (double)INT_MIN)
{
item->valueint = INT_MIN;
}
else
{
item->valueint = (int)num;
}
}
return item;
}
这个函数首先调用cJSON_New_Item
函数来分配一个新的cJSON对象。然后,将新对象的类型设置为cJSON_Number
,并将传入的数字值赋给valuedouble
成员。同时,它还处理了数字值的溢出情况。
cJSON_CreateString
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_String;
item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
if(!item->valuestring)
{
cJSON_Delete(item);
return NULL;
}
}
return item;
}
这个函数首先调用cJSON_New_Item
函数来分配一个新的cJSON对象。然后,将新对象的类型设置为cJSON_String
,并将传入的字符串值复制到valuestring
成员。如果字符串复制失败,那么就释放这个新对象,并返回NULL。
cJSON_strdup函数
static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
{
size_t length = 0;
unsigned char *copy = NULL;
if (string == NULL)
{
return NULL;
}
length = strlen((const char*)string) + sizeof("");
copy = (unsigned char*)hooks->allocate(length);
if (copy == NULL)
{
return NULL;
}
memcpy(copy, string, length);
return copy;
}
cJSON_strdup
函数是cJSON库中的一个内部函数,它的作用是复制字符串。
在C语言中,字符串是通过字符数组来表示的,而复制字符串通常需要分配一块新的内存,然后将原字符串的内容复制到新的内存中。cJSON_strdup
函数就是用来完成这个任务的。
在cJSON_CreateString
函数中,cJSON_strdup
被用来复制传入的字符串值。这个复制的过程是必要的,因为我们不能保证传入的字符串在以后的使用中不会被修改或释放。通过复制字符串,我们可以确保cJSON对象中的字符串值是安全和稳定的。
需要注意的是,cJSON_strdup
在内部调用了malloc
为变量分配内存,所以在不需要使用返回的字符串时,需要用free
释放相应的内存空间,否则会造成内存泄漏。
他的实现原理就是使用hooks->allocate
复制出你需要的内存空间,然后memcpy
把参数的内容复制进去仅此而已
cJSON_Delete函数
函数实现:
/* Delete a cJSON structure. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
{
cJSON *next = NULL;
while (item != NULL)
{
next = item->next;
if (!(item->type & cJSON_IsReference) && (item->child != NULL))
{
cJSON_Delete(item->child);
}
if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
{
global_hooks.deallocate(item->valuestring);
item->valuestring = NULL;
}
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
{
global_hooks.deallocate(item->string);
item->string = NULL;
}
global_hooks.deallocate(item);
item = next;
}
}
这三个条件语句块是在处理cJSON对象的内存释放时使用的。具体来说:
-
if (!(item->type & cJSON_IsReference) && (item->child != NULL))
:这个条件语句块会在cJSON对象的child
字段不为空,并且该对象不是对child
的引用时执行。也就是说,如果这个cJSON对象拥有自己的child
对象,那么在释放这个cJSON对象的内存时,也需要释放其child
对象的内存。 -
if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
:这个条件语句块会在cJSON对象的valuestring
字段不为空,并且该对象不是对valuestring
的引用时执行。也就是说,如果这个cJSON对象拥有自己的valuestring
字符串,那么在释放这个cJSON对象的内存时,也需要释放其valuestring
字符串的内存。 -
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
:这个条件语句块会在cJSON对象的string
字段不为空,并且该字符串不是常量时执行。也就是说,如果这个cJSON对象拥有自己的string
字符串,并且这个字符串可以修改,那么在释放这个cJSON对象的内存时,也需要释放其string
字符串的内存。
在分支1中,递归cJSON_Delete
,为什么要这样做?
因为我们并不知道一个child里面是单纯的键值对,还是有一堆对象和数组嵌套的,所以我们把child当作当个item去处理,这样就可以把最深层的键值对和其他的清除掉了。
最后一句怎么理解?
总结
通过深入研究CJson的源码和创建不同类型键值对的方法,我们可以更好地理解如何在JSON对象中添加和处理各种类型的数据。这些知识对于理解CJson的功能和性能至关重要。希望通过本文的阅读,你能对CJson有一个更深入的理解,也能在你的编程实践中更有效地使用JSON数据格式。未来,我们还将继续探索更多关于CJson的主题,包括它的性能优化,错误处理,以及如何在特定的应用场景中使用CJson。
- 点赞
- 收藏
- 关注作者
评论(0)