00. 目录

01. JSON概述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它是基于 JavaScript 的一种字符串格式,独立于编程语言,可以用来存储和传输数据。JSON 数据可以是简单的数字、字符串、数组或其他复杂数据类型。它通常用于 Web 应用程序中,用于存储和传输数据,也可以用于其他应用程序中。 JSON 格式由一系列特定的字符组成,这些字符称为“键”和“值”。键通常是字符串,值可以是字符串、数字、布尔值、数组或另一个 JSON 对象。在 JSON 中,数组和对象是通过花括号 [] 和 {} 包裹起来的,每个元素由逗号 , 分隔。

在这里插入图片描述

02. JSON下载

下载:https://github.com/DaveGamble/cJSON

03. JSON中ifndef

#ifndef cJSON__h
#define cJSON__h

#ifdef __cplusplus
extern "C"
{
#endif
    
    
#ifdef __cplusplus
}
#endif

#endif
    

#ifndef cJSON_h, #define cJSON_h, #endif . 为了防止头文件被重复引用。

extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。

04. JSON版本

/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 15

05. JSON类型

/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False  (1 << 0)
#define cJSON_True   (1 << 1)
#define cJSON_NULL   (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array  (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw    (1 << 7) /* raw json */

#define cJSON_IsReference 256
#define cJSON_StringIsConst 512

这些宏定义是对结构体type的值定义,处理时只需要将type的值0xFF进行位运算,即可得到json里储存的数据类型。

06. JSON结构体

/* The cJSON structure: */
typedef struct cJSON
{
    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    struct cJSON *next;
    struct cJSON *prev;
    /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    struct cJSON *child;

    /* The type of the item, as above. */
    int type;

    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    int valueint;
    /* The item's number, if type==cJSON_Number */
    double valuedouble;

    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    char *string;
} cJSON;

cJSON用了一个结构体来表示一个JSON的数据,它不是将一整段的JSON数据全部抽象出来,而将把其中的一条JSON数据抽象出来。

cJSON的存储结构像一个广义表,也可以说是一个树,不过兄弟结点之间都通过prev和next两个指针连接起来。

prev和next分别是cJSON对象的前驱和后继,属于同一级别的对象。chid则指向孩子结点,并且是第一个孩子的指针。

结构体成员 type 变量用于描述数据元素的类型(如果是键值对表示 value 值的类型),数据元素可以是字符串可以是整形,也可以是浮点型。

  • 如果是整形值的话可通过 valueint 将值取出
  • 如果是浮点型的话可通过 valuedouble 将值取出
  • 如果是字符串类型的话可通过 valuestring 将值取出
  • 结构体成员 string 表示键值对中键值的名称。

07. cJSON_Hooks结构体

typedef struct cJSON_Hooks
{
      /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
      void *(CJSON_CDECL *malloc_fn)(size_t sz);
      void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;

定义了malloc函数以及free函数,malloc 函数其实就是分配内存,free函数就是释放内存。

08. cJSON_InitHooks函数

CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
{
    if (hooks == NULL)
    {
        /* Reset hooks */
        global_hooks.allocate = malloc;
        global_hooks.deallocate = free;
        global_hooks.reallocate = realloc;
        return;
    }

    global_hooks.allocate = malloc;
    if (hooks->malloc_fn != NULL)
    {
        global_hooks.allocate = hooks->malloc_fn;
    }

    global_hooks.deallocate = free;
    if (hooks->free_fn != NULL)
    {
        global_hooks.deallocate = hooks->free_fn;
    }

    /* use realloc only if both free and malloc are used */
    global_hooks.reallocate = NULL;
    if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
    {
        global_hooks.reallocate = realloc;
    }
}

realloc函数、malloc函数和free函数,则指针指向自定义的函数,否则指向默认函数。

09. cJSON Item创建

/* These calls create a cJSON item of the appropriate type. */
//空值类型
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);

//布尔类型
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);

// 数值类型
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);

// 字符串类型
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);


/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);

// json数组(创建空数组)
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);

// json对象(创建空对象)
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);

10. 判断JSON类型

/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);

11. JSON数组

/* These utilities create an Array of count items.
 * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
// 创建一个Json数组, 元素为整型
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
// 创建一个Json数组, 元素为浮点
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);

CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
// 创建一个Json数组, 元素为字符串类型
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);

/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);

添加数据到 Json 数组中(原始数据需要先转换为 cJSON 结构体类型)

/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);

Json 数组中元素的个数:

/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);

Json 数组中指定位置的元素,如果返回 NULL 表示取值失败。

/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);

12. JSON对象


/* Helper functions for creating and adding items to an object at the same time.
 * They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);

当得到一个 Json 对象之后,就可以往对象中添加键值对了,可以使用 cJSON_AddItemToObject()

  • object:要添加的键值对从属于那个节点
  • string:添加的键值对的键值
  • item:添加的键值对的 value 值(需要先将其封装为 cJSON 类型的结构体)

我们还可以根据 Json 对象中的键值取出相应的 value 值,API 函数原型如下:

/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);

13. JSON序列化

序列化就是将 Json 格式的数据转换为字符串的过程

/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
  • 调用 cJSON_Print() 函数我们可以得到一个带格式的 Json 字符串(有换行,看起来更方便)

  • 调用 cJSON_PrintUnformatted() 函数会得到一个没有格式的 Json 字符串(没有换行)。

  • 调用 cJSON_PrintBuffered() 函数使用缓冲策略将 Json 实体转换为字符串,参数 prebuffer 是指定缓冲区的大小,参数 fmt0 表示未格式化,fmt1 表示格式化。

在实际开发过程中可以根据自己的实际需求调用相关的操作函数得到对应格式的 Json 字符串。

14. JSON解析

如果我们收到了一个 Json 格式的字符串,想要读出里边的数据,就需要对这个字符串进行解析,处理方式就是将字符串转换为 cJSON 结构体,然后再基于这个结构体读里边的原始数据,转换函数的函数原型如下:

/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);

15. JSON内存管理

当我们将数据封装为 cJSON 结构类型的节点之后都会得到一块堆内存,当我们释放某个节点的时候可以调用 cJson 库提供的删除函数 cJSON_Delete(),函数原型如下:

/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);

该函数的参数为要释放的节点的地址,在此强调一点:在进行内存地址释放的时候,当前节点以及其子节点都会被删除。

16. 附录

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐