CJson源码解析之cJSON_CreateObject函数

发布于:2024-07-01 ⋅ 阅读:(13) ⋅ 点赞:(0)


前言

在现代编程中,JSON已经成为了一种非常流行的数据交换格式。它的简洁性和易读性使得开发者可以轻松地在不同的系统和应用之间共享和理解数据。CJson是一个轻量级的JSON解析库,它提供了一种简单和高效的方式来解析和生成JSON数据。本文将深入探讨CJson的源码,特别是它的核心函数cJSON_CreateObject。


cJSON_CreateObject的作用

cJSON_CreateObject函数是cJSON库中的一个核心函数,它的主要作用是创建一个新的JSON对象
在调用cJSON_CreateObject函数后,它会在内存中为新的JSON对象分配空间,并返回一个指向这个新对象的指针
这个新创建的JSON对象可以被看作是一个空的JSON对象(即{}),你可以通过调用其他cJSON函数(如cJSON_AddItemToObject)向这个对象中添加键值对。

代码详解

函数的实现:

CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if (item)
    {
        item->type = cJSON_Object;
    }

    return item;
}

三个有关库的导出宏

首先我们需要先介绍符号的导入和导出:
在编程中,"符号"通常指的是变量名、函数名等标识符。在编译和链接过程中,这些符号会被转换为内存地址。

  • 导出符号:当一个模块(例如一个库)希望让其他模块能够访问它的某些函数或变量时,它需要将这些函数或变量的符号导出。这样,其他模块就可以通过这些导出的符号来调用这些函数或访问这些变量。

  • 导入符号:当一个模块希望使用另一个模块导出的符号时,它需要导入这些符号。这样,它就可以通过这些导入的符号来调用函数或访问变量。

例如,假设我们有两个模块A和B。模块A定义了一个函数foo,并将foo的符号导出。然后,模块B可以导入foo的符号,并通过这个符号来调用foo函数。

CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol

这三个宏定义是用于控制cJSON库中符号的导出和导入的。在Windows环境下,这些宏定义与动态链接库(DLL)的创建和使用有关。

  • CJSON_HIDE_SYMBOLS:如果你不希望导出任何符号,就定义这个宏。这意味着cJSON库中的函数和变量不会被导出到DLL。

  • CJSON_EXPORT_SYMBOLS:在构建库时,如果你希望导出符号,就定义这个宏。这是默认设置,意味着cJSON库中的函数和变量会被导出到DLL。

  • CJSON_IMPORT_SYMBOLS:如果你希望从DLL中导入符号,就定义这个宏。这通常在使用DLL的应用程序中定义。

当你编译cJSON库并将其作为DLL使用时,你需要在编译cJSON源文件时定义CJSON_EXPORT_SYMBOLS宏,这样cJSON库中的函数和变量就会被导出到DLL。

然后,当你在另一个C文件中使用这个DLL时,你需要在包含cJSON头文件的地方定义CJSON_IMPORT_SYMBOLS宏。这样,你就可以从DLL中导入cJSON库中的函数和变量,然后在你的C文件中使用这些函数和变量。

CJSON_PUBLIC的作用

CJSON_PUBLIC的定义如下:

#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type)   type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type)   __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type)   __declspec(dllimport) type CJSON_STDCALL
#endif

通过上一个标题的里面的宏变化,就可以让dll有不同的状态

cJSON_CreateObject第一行解析

他的第一行使用函数创建一个cJSON*类型 item作为返回值返回.

cJSON *item = cJSON_New_Item(&global_hooks);

他调用了cJSON_New_Item函数
他的实现如下:

static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
{
    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
    if (node)
    {
        memset(node, '\0', sizeof(cJSON));
    }

    return node;
}

cJSON_New_Item函数解析

参数

他的参数是这样的:const internal_hooks * const hooks
他是一个结构体:

typedef struct internal_hooks
{
    void *(CJSON_CDECL *allocate)(size_t size);
    void (CJSON_CDECL *deallocate)(void *pointer);
    void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
} internal_hooks;

这个internal_hooks结构体在cJSON库中用于管理内存的分配、释放和重新分配。它包含了三个函数指针,每个函数指针都对应一个内存管理操作:

  • allocate:这个函数用于分配指定大小的内存。它接受一个size_t类型的参数,表示需要分配的内存的大小,然后返回一个指向新分配内存的指针。

  • deallocate:这个函数用于释放之前分配的内存。它接受一个指向需要释放内存的指针,然后释放这块内存。

  • reallocate:这个函数用于重新分配内存。它接受一个指向需要重新分配的内存的指针和一个size_t类型的参数,表示新的内存大小,然后返回一个指向重新分配后的内存的指针。

通过这些函数我们就可以使用他们申请我们的cJSON对象,并且因为他们是自己写的,可控的,在不同编译器和环境是一样的,所以就不会导致错误的发生
,或者不同行为的产生

cJSON内存的申请

我们可以通过internal_hooks 成员申请一个cJSON类型大小的指针,用来存储我们的json对象

cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));

紧接着我们判断node是否申请成功,并初始化内存

cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
if (node)
{
    memset(node, '\0', sizeof(cJSON));
}

判断并设置cJSON类型

首先,还是要进行合法性判断,然后把item的type设置为cJSON_Object,标识他为一个对象

if (item)
{
    item->type = cJSON_Object;
}

总结

通过深入研究CJson的源码和cJSON_CreateObject函数,我们可以更好地理解如何创建JSON对象,以及如何有效地解析和生成JSON数据。cJSON_CreateObject函数的设计和实现对于理解CJson的功能和性能至关重要。希望通过本文的阅读,你能对CJson有一个更深入的理解,也能在你的编程实践中更有效地使用JSON数据格式。未来,我们还将继续探索更多关于CJson的主题,包括它的性能优化,错误处理,以及如何在特定的应用场景中使用CJson。


网站公告

今日签到

点亮在社区的每一天
去签到