CJson源码解析之创建不同类型的键值对

举报
人才程序员 发表于 2024/09/14 19:06:09 2024/09/14
【摘要】 @TOC 前言在现代编程中,JSON已经成为了一种非常流行的数据交换格式。它的简洁性和易读性使得开发者可以轻松地在不同的系统和应用之间共享和理解数据。CJson是一个轻量级的JSON解析库,它提供了一种简单和高效的方式来解析和生成JSON数据。本文将深入探讨CJson的源码,特别是它如何创建不同类型的键值对。这段代码比较简单,这里简单略过 cJSON_CreateNullCJSON_PUBL...

@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_TruecJSON_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对象的内存释放时使用的。具体来说:

  1. if (!(item->type & cJSON_IsReference) && (item->child != NULL)):这个条件语句块会在cJSON对象的child字段不为空,并且该对象不是对child的引用时执行。也就是说,如果这个cJSON对象拥有自己的child对象,那么在释放这个cJSON对象的内存时,也需要释放其child对象的内存。

  2. if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)):这个条件语句块会在cJSON对象的valuestring字段不为空,并且该对象不是对valuestring的引用时执行。也就是说,如果这个cJSON对象拥有自己的valuestring字符串,那么在释放这个cJSON对象的内存时,也需要释放其valuestring字符串的内存。

  3. 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。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。