【C/C++业务】cJSON总结与使用

cJSON的下载和安装

  1. 源码下载:
    • 地址一:git clone https://github.com/DaveGamble/cJSON.git
   //安装和编译
   mkdir build
   cd build
   cmake ..
   make
   sudo make install
  • 地址二:https://sourceforge.net/projects/cjson/
  1. 解压 unzip XXX.zip
  2. cJson.c,cJSON.h拷贝到自定义的目录
  3. 编译:gcc cJSON.c test.c -o test -lm(添加数学库)
  4. 基于JSON相关的c函数库,生成json文件

cJSON函数分析

cJSON函数库的核心结构体就是一个cJSON

  • cJSON是使用链表来存储数据的,其访问方式像一颗树。每一个节点可以有兄弟节点,通过next/prev指针来查找,它类似双向链表;每个节点也可以有孩子节点,通过child指针来访问,进入下一层。只有节点是对象或数组时才可以有孩子节点。
  • type是键(key)的类型,一共有7种取值,分别是:FalseTureNULLNumberStringArrayObject。若是Number类型,则valueintvaluedouble中存储值。若期望的是int,则访问valueint;若期望的是double,则访问valuedouble,可以得到值。若是String类型的,则valuestring中存储值,可以访问valuestring得到值。
  • string中存放的是这个节点的名字,可理解为key的名称。
#define cJSON_Invalid (0)
#define cJSON_False  (1 << 0)//1
#define cJSON_True   (1 << 1)//2
#define cJSON_NULL   (1 << 2)//4
#define cJSON_Number (1 << 3)//8
#define cJSON_String (1 << 4)//16
#define cJSON_Array  (1 << 5)//32
#define cJSON_Object (1 << 6)//64
#define cJSON_Raw    (1 << 7)//128 /* raw json */

#define cJSON_IsReference 256
#define cJSON_StringIsConst 512

typedef struct cJSON {
       struct cJSON *next,*prev;          /* 遍历数组或对象链的前向或后向链表指针*/
       struct cJSON *child;               /* 数组或对象的孩子节点*/
       int type;                          /* key的类型*/
       char *valuestring;                 /* 字符串值*/
       int valueint;                      /* 整数值*/
       double valuedouble;                /* 浮点数值*/
       char *string;                      /* key的名字*/
} cJSON;

JSON的三种语法

  • 键/值对key:value,用半角冒号分割。比如"name":"Faye"
  • 文档对象JSON对象写在花括号中,可以包含多个键/值对。比如{"name":"Faye", "address":"北京"}
  • 数组JSON数组在方括号中书写:数组成员可以是对象、值,也可以是数组(只要有意义)。比如{"love": ["乒乓球","高尔夫","斯诺克","羽毛球","LOL","撩妹"]}

JSON的两种结构

  • 对象:表示为“{}”括起来的内容,数据结构为{key:value,key:value,...}的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值;
  • 数组:表示为中括号“[]”括起来的内容,数据结构为["java","javascript","vb",...],取值方式和所有语言中一样,使用索引获取。

写JSON文件的函数

//将传入的JSON结构转化为字符串,将cJSON数据解析成JSON字符串,并在堆中开辟一块char*的内存空间存储JSON字符串。
/* Render a cJSON item/entity/structure to text. */
char *cJSON_Print(cJSON *item)				{return print_value(item,0,1,0);}
char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0,0);}

//创建一个值类型的数据
cJSON *cJSON_CreateNumber(double num);
cJSON *cJSON_CreateString(const char *string);
cJSON *cJSON_CreateArray(void);
//创建一个对象(文档)
cJSON *cJSON_CreateObject(void);

//将创建的cJSON数组/对象添加到链表中
cJSON *cJSON_CreateIntArray(const int *numbers,int count);
/* Append item to the specified array/object. */
void cJSON_AddItemToArray(cJSON *array, cJSON *item);
void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);

//从现有的cJSON链表中删除一个对象
/* Remove/Detatch items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);

//创建并添加cJSON对象到指定的链表
/* 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);

//JSON嵌套 :
【 向对象中增加键值对】 cJSON_AddItemToObject(root, “rows”, 值类型数据相关函数());
【 向对象中增加数组】   cJSON_AddItemToObject(root, “rows”, cJSON_CreateArray());
【 向数组中增加对象】   cJSON_AddItemToArray(rows, cJSON_CreateObject());

//几个能提高操作效率的宏函数 :
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name,cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))

解析JSON格式的函数

//cJSON_Parse解析JSON数据包,并按照cJSON结构体的结构序列化整个数据包。使用该函数会通过malloc()函数在内存中开辟空间,使用完需要手动释放。cJSON *root=cJSON_Parse(json_string); 
cJSON *cJSON_Parse(const char *value);

//cJSON_GetObjectItem从cJSON结构体中查找某个子节点名称(键名称),如果查找成功可把该子节点序列化到cJSON结构体中。cJSON *item=cJSON_GetObjectItem(root,"firstName"); 
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);

//cJSON_Delete用于释放cJSON_Parse()分配出来的内存空间。cJSON_Delete(root);
void cJSON_Delete(cJSON *c); 

//获取数组长度
int cJSON_GetArraySize(cJSON *array);
//获取数组成员,根据数组下标index取array数组结点的第index个成员 返回该成员节点
cJSON *cJSON_GetArrayItem(cJSON *array,int item); c

//根据键找json结点 :
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)
    
//遍历数组 :
#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)

cJSON使用实例

  • 实例一:简单解析JSON数据
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

char text[] = "{\"timestamp\":\"2020-08-10 08:45:57\", \"value\":1}";

int main(int argc, const char *argv[])
{
    cJSON *json, *json_value, *json_timestamp;

    json = cJSON_Parse(text);
    if(NULL == json)
    {
        printf("Error before: [%s]\n", cJSON_GetErrorPtr());
        return -1;
    }

    json_value = cJSON_GetObjectItem(json, "value");
    if(json_value->type == cJSON_Number)
    {
        printf("value: %d\n", json_value->valueint);
    }

    json_timestamp = cJSON_GetObjectItem(json, "timestamp");
    if(json_timestamp->type == cJSON_String)
    {
        printf("%s\n", json_timestamp->valuestring);
    }

    cJSON_Delete(json);

    return 0;
}

输出:

value: 1
2020-08-10 08:45:57
  • 实例二:按不同要求解析json的方法
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

void printJson(cJSON * root)//以递归的方式打印json的最内层键值对
{
    int i = 0;
    for(; i<cJSON_GetArraySize(root); i++)   //遍历最外层json键值对
    {
        cJSON * item = cJSON_GetArrayItem(root, i);        
        if(cJSON_Object == item->type)      //如果对应键的值仍为cJSON_Object就递归调用printJson
            printJson(item);
        else                                //值不为json对象就直接打印出键和值
        {
            printf("%s->", item->string);
            printf("%s\n", cJSON_Print(item));
        }
    }
}

int main()
{
    char * jsonStr = "{\"semantic\":{\"slots\":{\"name\":\"张三\"}}, \"rc\":0,       \
    \"operation\":\"CALL\", \"service\":\"telephone\", \"text\":\"打电话给张三\"}";
    cJSON * root = NULL;
    cJSON * item = NULL;//cjson对象

    root = cJSON_Parse(jsonStr);     
    if (!root) 
    {
        printf("Error before: [%s]\n",cJSON_GetErrorPtr());
    }
    else
    {
        printf("%s\n", "有格式的方式打印Json:");           
        printf("%s\n\n", cJSON_Print(root));
        printf("%s\n", "无格式方式打印json:");
        printf("%s\n\n", cJSON_PrintUnformatted(root));

        printf("%s\n", "一步一步的获取name 键值对:");
        printf("%s\n", "获取semantic下的cjson对象:");
        item = cJSON_GetObjectItem(root, "semantic");//
        printf("%s\n", cJSON_Print(item));
        printf("%s\n", "获取slots下的cjson对象");
        item = cJSON_GetObjectItem(item, "slots");
        printf("%s\n", cJSON_Print(item));
        printf("%s\n", "获取name下的cjson对象");
        item = cJSON_GetObjectItem(item, "name");
        printf("%s\n", cJSON_Print(item));

        printf("%s:", item->string);   //看一下cjson对象的结构体中这两个成员的意思
        printf("%s\n", item->valuestring);
                        

        printf("\n%s\n", "打印json所有最内层键值对:");
        printJson(root);
    }
    return 0;    
}

输出:

有格式的方式打印Json:
{
        "semantic":     {
                "slots":        {
                        "name": "张三"
                }
        },
        "rc":   0,
        "operation":    "CALL",
        "service":      "telephone",
        "text": "打电话给张三"
}

无格式方式打印json:
{"semantic":{"slots":{"name":"张三"}},"rc":0,"operation":"CALL","service":"telephone","text":"打电话给张三"}

一步一步的获取name 键值对:
获取semantic下的cjson对象:
{
        "slots":        {
                "name": "张三"
        }
}
获取slots下的cjson对象
{
        "name": "张三"
}
获取name下的cjson对象
"张三"
name:张三

打印json所有最内层键值对:
name->"张三"
rc->0
operation->"CALL"
service->"telephone"
text->"打电话给张三"
  • 实例三:创建JSON数据
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

int main(void)
{
    char *cjson_str = NULL;
    cJSON * root =  cJSON_CreateObject();
    cJSON * item =  cJSON_CreateObject();
    cJSON * next =  cJSON_CreateObject();

    cJSON_AddItemToObject(root, "rc", cJSON_CreateNumber(0));//根节点下添加
    cJSON_AddItemToObject(root, "operation", cJSON_CreateString("CALL"));
    cJSON_AddItemToObject(root, "service", cJSON_CreateString("telephone"));
    cJSON_AddItemToObject(root, "text", cJSON_CreateString("打电话给张三"));
    cJSON_AddItemToObject(root, "semantic", item);//root节点下添加semantic节点
    cJSON_AddItemToObject(item, "slots", next);//semantic节点下添加item节点
    cJSON_AddItemToObject(next, "name", cJSON_CreateString("张三"));//添加name节点

    //cjson_str = cJSON_Print(root);
    cjson_str =cJSON_PrintUnformatted(root);
    printf("first json:\n%s\n", cjson_str);
    free(cjson_str);

    cJSON_AddStringToObject(next, "number", "13423452334");
    cJSON_AddNumberToObject(next, "age", 35);
    cJSON_AddBoolToObject(next, "man", 1);

    //cjson_str = cJSON_Print(root);
    cjson_str =cJSON_PrintUnformatted(root);
    printf("second json:\n%s\n", cjson_str);
    free(cjson_str);

    cJSON_Delete(root);

    return 0;
}

输出:

first json:
{"rc":0,"operation":"CALL","service":"telephone","text":"打电话给张三","semantic":{"slots":{"name":"张三"}}}
second json:
{"rc":0,"operation":"CALL","service":"telephone","text":"打电话给张三","semantic":{"slots":{"name":"张三","number":"13423452334","age":35,"man":true}}}
  • 实例四:创建Array的JSON数据
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

char *makeArray(int iSize)
{
    int i;
    char *out = NULL;

    cJSON *root = cJSON_CreateArray();
    if(NULL == root)
    {
        printf("create json array failed!");
        return NULL;
    }

    for(i = 0; i < iSize; i++)
    {
        cJSON_AddNumberToObject(root, "hehe", i + 1);
    }

    out = cJSON_Print(root);
    cJSON_Delete(root);
    return out;
}

void parseArray(char *pJson)
{
    int i = 0;
    int iSize = 0;
    cJSON *root = NULL;

    if(NULL == pJson)
        return;

    root = cJSON_Parse(pJson);
    if(NULL == root)
        return;

    iSize = cJSON_GetArraySize(root);
    for(i = 0; i < iSize;i++)
    {
        cJSON *psub = cJSON_GetArrayItem(root, i);
        if(NULL == psub)
            continue;
        printf("value[%2d] : %d\n", i, psub->valueint);
    }

    cJSON_Delete(root);
}

int main(void)
{
    char *json = NULL;
    
    json = makeArray(5);
    printf("create json: %s\n", json);
    parseArray(json);
    free(json);

    return 0;
}

输出:

create json: [1, 2, 3, 4, 5]
value[ 0] : 1
value[ 1] : 2
value[ 2] : 3
value[ 3] : 4
value[ 4] : 5
  • 实例五

json数据采用链表存储

typedef struct cJSON {  
    struct cJSON *next,*prev;   // 数组 对象数据中用到  
    struct cJSON *child;        // 数组 和对象中指向子数组对象或值  
  
    int type;           // 元素的类型,如是对象还是数组  
  
    char *valuestring;          // 如果是字符串  
    int valueint;               // 如果是数值  
    double valuedouble;         // 如果类型是cJSON_Number  
  
    char *string;               // The item's name string, if this item is the child of, or is in the list of subitems of an object.  
} cJSON;  

如果有一个json数据

{  
    "name": "Jack (\"Bee\") Nimble",   
    "format": {  
        "type":       "rect",   
        "width":      1920,   
        "height":     1080,   
        "interlace":  false,   
        "frame rate": 24  
    }  
}  

可以进行如下操作

//将字符串解析成json结构体
cJSON *root = cJSON_Parse(my_json_string);  
//获取某个元素
cJSON *format = cJSON_GetObjectItem(root,"format");  
int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint;  
//json结构体转换成字符串
char *rendered=cJSON_Print(root); 
//删除json结构体
cJSON_Delete(root);  
//构建一个json结构体
cJSON *root,*fmt;  
root=cJSON_CreateObject();    
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));  
cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());  
cJSON_AddStringToObject(fmt,"type",     "rect");  
cJSON_AddNumberToObject(fmt,"width",        1920);  
cJSON_AddNumberToObject(fmt,"height",       1080);  
cJSON_AddFalseToObject (fmt,"interlace");  
cJSON_AddNumberToObject(fmt,"frame rate",   24);  
  • 实例六:将json数据写入文件
void WriteJson()
{
    char *char_json = "{\"hello\":\"你好\"}";

    //从缓冲区中解析出JSON结构
    cJSON *json = cJSON_Parse(char_json);

    if (json == NULL)
    {
        return;
    }

    //将传入的JSON结构转化为字符串 
    char *buf = NULL;
     buf = cJSON_Print(json);

    //打开一个info.json文件,并写入json内容
    FILE *fp = fopen("info.json", "w");
    fwrite(buf, strlen(buf), 1, fp);

    fclose(fp);//关闭文件
    free(buf);//释放资源
    cJSON_Delete(json);//释放资源
}

int main()
{
  WriteJson();
  return 0;
}

其他参考:https://zhuanlan.zhihu.com/p/51781273

cJSON内存泄露注意事项

申请内存释放内存
cJSON_ParsecJSON_Delete
cJSON_CreatecJSON_Delete
cJSON_PrintcJSON_free
  • 在cjson中释放内存时,只需要释放父节点就可以,不需要专门管理子节点,子节点会随着父节点的释放一并释放掉,即通过cJSON_AddItemToObject函数加入到数组或者object中,不需要单独释放new_json ,删除json对象时被添加的new_json同时也会被删除。对于子节点,最好的做法是在程序处理完成数据后,判断一下每个节点是不是NULL。

  • cjson中的string类型数据在写入时是内存拷贝,并不是内存指向,cjson中占用的内存,会在删除父节点的时候一并被释放掉。

  • 字符串格式化函数调用后返回的字串内存,需要专门调用free函数释放掉

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UC/OS-II 是一个实时操作系统,而 cJSON 是一个轻量级的 JSON 解析器和生成器库。如果你想在 UC/OS-II 中使用 cJSON,你需要将 cJSON 的源代码添加到你的项目中,并进行相应的配置。 以下是在 UC/OS-II 中使用 cJSON 的一般步骤: 1. 将 cJSON 的源代码添加到你的 UC/OS-II 项目中。可以将 cJSON 的源文件(cJSON.c 和 cJSON.h)直接复制到你的项目目录中,或者将其放在一个单独的文件夹中,并将该文件夹添加到你的项目的 include 路径中。 2. 在你的 UC/OS-II 任务中包含 cJSON 头文件,并在任务初始化的地方进行 cJSON 的初始化。例如,你可以在任务初始化函数中调用 `cJSON_Init()` 函数来初始化 cJSON: ```c #include "cJSON.h" void YourTask(void *p_arg) { // 初始化 cJSON cJSON_Init(); // 其他任务代码... } ``` 3. 在你的任务中使用 cJSON 解析和生成 JSON 数据。你可以使用 cJSON 的 API 来解析和生成 JSON 数据。例如,使用 `cJSON_Parse()` 函数解析 JSON 字符串,使用 `cJSON_CreateObject()` 和 `cJSON_AddItemToObject()` 函数创建和添加 JSON 对象等。 以下是一个简单的例子,演示了如何使用 cJSON 解析和生成 JSON 数据: ```c #include "cJSON.h" void YourTask(void *p_arg) { cJSON *root = NULL; char *jsonStr = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}"; // 解析 JSON 字符串 root = cJSON_Parse(jsonStr); if (root != NULL) { // 从 JSON 对象中获取字段值 cJSON *name = cJSON_GetObjectItem(root, "name"); cJSON *age = cJSON_GetObjectItem(root, "age"); cJSON *city = cJSON_GetObjectItem(root, "city"); if (name != NULL && age != NULL && city != NULL) { // 打印字段值 printf("Name: %s\n", name->valuestring); printf("Age: %d\n", age->valueint); printf("City: %s\n", city->valuestring); } // 释放 cJSON 对象 cJSON_Delete(root); } // 生成 JSON 对象 cJSON *newRoot = cJSON_CreateObject(); cJSON_AddStringToObject(newRoot, "name", "Alice"); cJSON_AddNumberToObject(newRoot, "age", 25); cJSON_AddStringToObject(newRoot, "city", "London"); // 将 JSON 对象转换为字符串 char *newJsonStr = cJSON_Print(newRoot); if (newJsonStr != NULL) { printf("New JSON string: %s\n", newJsonStr); free(newJsonStr); } // 释放 cJSON 对象 cJSON_Delete(newRoot); // 其他任务代码... } ``` 这只是一个简单的示例,你可以根据你的具体需求使用其他 cJSON 的 API 来解析和生成 JSON 数据。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值