提醒:文章最后说明讲解ESP IDF组件库的cJSON库调用

一、cJSON基础

json轻量级的数据交换格式

        json语法规则:

  • 数据在名称/值对中。
  • 数据由逗号分隔。
  • 大括号{ }保存对象。
  • 中括号[ ]保存数组,数组可以包含多个对象。

cJSON使用cJSON结构数据类型表示JSON数据,数据类型如下

/* The cJSON structure: */
typedef struct cJSON
{
    struct cJSON *next;
    struct cJSON *prev;
    struct cJSON *child;
    int type;
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    int valueint;
    double valuedouble;
    char *string;
} cJSON;

1.cJOSN结构体为一个双向列表,并可通过child指针访问下一层。

2.type变量决定数据项类型(值的类型),数据项可以是字符串可以是整形,也可以是浮点型。如果是整形值的话可从valueint,如果是浮点型的话可从valuedouble取出,以此类推。

3.string可理解为节点的名称,即为键

二、cJSON数据封装

封装JSON数据的过程,其实就是创建链表和向链表中添加节点的过程。

首先来讲述一下链表中的一些术语:

  • 头指针:指向链表头结点的指针;
  • 头结点:不存放有效数据,方便链表操作;
  • 首节点:第一个存放有效数据的节点;
  • 尾节点:最后一个存放有效数据的节点;

明白了这几个概念之后,我们开始讲述创建一段完整的JSON数据,即如何创建一条完整的链表。

cJSON重要函数说明

  • 创建链表头指针
(cJSON* ) cjson_pointer = NULL;
  • 创建一个JSON数据对象
(cJSON *) cJSON_CreateObject(void);
  • 创建一个JSON数组对象
(cJSON *) cJSON_CreateArray(void);
  • 添加一条字符串类型的JSON数据(添加一个链表节点)
cJSON* cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
  • 添加一条整数类型的JSON数据(添加一个链表节点)
cJSON* cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
  • JSON嵌套

向对象中添加

cJSON_bool cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);

向数组中添加

void cJSON_AddItemToArray(cJSON *array, cJSON *item);
  • 解析整段JSON数据,并将链表头结点地址返回,赋值给头指针
(cJSON *) cJSON_Parse(const char *value);
  • 根据键值对的名称从链表中取出对应的值,返回该键值对(链表节点)的地址
(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
  • 如果JSON数据的值是数组,使用下面的两个API提取数据
(int) cJSON_GetArraySize(const cJSON *array);
(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
  • cJSON_Delete() 会删除一个节点的所有兄弟结点和以它们为根的子树
(void) cJSON_Delete(cJSON *item);

cJSON的所有操作都是基于链表的,所以cJSON在使用过程中大量的使用malloc从堆中分配动态内存的,所以在使用完之后,应当及时调用下面的函数,清空cJSON指针所指向的内存,该函数也可用于删除某一条数据:

注意:该函数删除一条JSON数据时,如果有嵌套,会连带删除。

  • cJSON提供了格式化打印json的方法:函数将json数据转成字符串

尽量只对没有兄弟结点的节点或根节点调用 cJSON_Delete()

(char *) cJSON_Print(const cJSON *item);

三、cJSON内存问题

        在esp32的程序代码中,与服务器通信需要创建大量的cJSON文本格式,因未正确操作cjson,导致内存泄漏,长时间运行程序后程序崩溃,需要严格采用内存申请释放的操作去对esp32的内存空间进行使用。

申请内存:

cJSON_Parse

cJSON_Create 

cJSON_Print

释放内存:

cJSON_Delete 

cJSON_Delete

 cJSON_free

四、ESP IDF组件中的cJSON库

找到ESP IDF组件的cJSON库文件夹

ESP-IDF已经将cjson库添加到ESP-IDF编译系统中,只需在esp32的程序代码中正常调用cjson的操作函数即可。

cJSON源码可在路径文件夹下直接打开查看

部分使用代码示例:


    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "cJSON.h"    //cJSON库
    
    cJSON *device_upload_cjson = NULL;
    char *access_data = NULL;   //接入数据
    char *upload_data = NULL;   //上传数据
    device_upload_cjson = cJSON_CreateObject();
    if (device_upload_cjson == NULL)
    {
        printf("Error before: [%s]\n", cJSON_GetErrorPtr());
        return -1;
    }
    cJSON_AddNumberToObject(device_upload_cjson, "ver",  1);    
    cJSON_AddNumberToObject(device_upload_cjson, "type", 1);   
    cJSON_AddNumberToObject(device_upload_cjson, "func", 101); 

GitHub 加速计划 / cj / cJSON
10.45 K
3.16 K
下载
Ultralightweight JSON parser in ANSI C
最近提交(Master分支:3 个月前 )
424ce4ce This reverts commit 5b502cdbfb21fbe5f6cf9ffbd2b96e4281a741e6. Related to #860 4 个月前
32497300 - 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐