cJSON

前言

  最近在研究物联网设备的数据传输,就想到了用JSON来进行,毕竟可以让设备数据对象化,同时各语言之间通常也有对于的解析器或库,来进行数据的获取。比如本文的介绍的cJSON就是作用于C语言上。文章主要内容,分析官方案例所用到的函数作用,来学习理解或快速回忆使用方法。

背景

  • 拉取cJSON-GitHub主页项目,并且将cJSON.hcJSON.c放到项目即可。(当然cJSON也提供几种针对不同环境的构建方法,暂时用不到就不赘述)
  • 若不熟悉JSON,可以参考JSON 教程 | 菜鸟教程

案例

  下面的构成和解析案例都是来自官方,功能函数的注释都是笔者自己的理解,如果和官方注解有冲突,请以官方的为准。还有只例出跟案例相关的函数,其余更多的函数可以自行阅读cJSON库文件。

案例所用的JSON结构:

{
    "name": "Awesome 4K",
    "resolutions": [
        {
            "width": 1280,
            "height": 720
        },
        {
            "width": 1920,
            "height": 1080
        },
        {
            "width": 3840,
            "height": 2160
        }
    ]
}

构成案例

基于官方构成JSON对象的案例来分析,使用到的函数作用。

代码案例1

让我们构建上面的JSON并将其打印为字符串:

//创建具有支持分辨率列表的监视器(笔者:这里并不是cJSON存在这个概念结构,而是该创建cJSON对象的数据意义)
//注意:返回一个堆分配的字符串,使用后需要释放它。
char *create_monitor(void)
{
    const unsigned int resolution_numbers[3][2] = {
        {1280, 720},
        {1920, 1080},
        {3840, 2160}
    };
    char *string = NULL;
    cJSON *name = NULL;
    cJSON *resolutions = NULL;
    cJSON *resolution = NULL;
    cJSON *width = NULL;
    cJSON *height = NULL;
    size_t index = 0;

    cJSON *monitor = cJSON_CreateObject();
    if (monitor == NULL)
    {
        goto end;
    }

    name = cJSON_CreateString("Awesome 4K");
    if (name == NULL)
    {
        goto end;
    }
    /* 创建成功后,立即将其添加到监视器中,从而将指针的所有权转移到它 */
    cJSON_AddItemToObject(monitor, "name", name);

    resolutions = cJSON_CreateArray();
    if (resolutions == NULL)
    {
        goto end;
    }
    cJSON_AddItemToObject(monitor, "resolutions", resolutions);

    for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    {
        resolution = cJSON_CreateObject();
        if (resolution == NULL)
        {
            goto end;
        }
        cJSON_AddItemToArray(resolutions, resolution);

        width = cJSON_CreateNumber(resolution_numbers[index][0]);
        if (width == NULL)
        {
            goto end;
        }
        cJSON_AddItemToObject(resolution, "width", width);

        height = cJSON_CreateNumber(resolution_numbers[index][1]);
        if (height == NULL)
        {
            goto end;
        }
        cJSON_AddItemToObject(resolution, "height", height);
    }

    string = cJSON_Print(monitor);
    if (string == NULL)
    {
        fprintf(stderr, "Failed to print monitor.\n");
    }

end:
    cJSON_Delete(monitor);
    return string;
}
代码案例2

另外,我们可以使用辅助函数使我们的工作更容易一些:cJSON_Add…ToObject。简化案例1的代码流程,大概流程思路是省略掉中间item项的声明定义过程,直接用函数一步到位。

//注意:返回一个堆分配的字符串,使用后需要释放它。
char *create_monitor_with_helpers(void)
{
    const unsigned int resolution_numbers[3][2] = {
        {1280, 720},
        {1920, 1080},
        {3840, 2160}
    };
    char *string = NULL;
    cJSON *resolutions = NULL;
    size_t index = 0;

    cJSON *monitor = cJSON_CreateObject();

    if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
    {
        goto end;
    }

    resolutions = cJSON_AddArrayToObject(monitor, "resolutions");
    if (resolutions == NULL)
    {
        goto end;
    }

    for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    {
        cJSON *resolution = cJSON_CreateObject();

        if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
        {
            goto end;
        }

        if (cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
        {
            goto end;
        }

        cJSON_AddItemToArray(resolutions, resolution);
    }

    string = cJSON_Print(monitor);
    if (string == NULL)
    {
        fprintf(stderr, "Failed to print monitor.\n");
    }

end:
    cJSON_Delete(monitor);
    return string;
}
构成案例函数

变量修饰符全部应该是CJSON_PUBLIC(cJSON *),还有个宏控制,下述就简化为(cJSON *)。还有下述描述函数用伪函数原形,也就是形参部分不写类型,而是写出应该输入的数据,如果觉得看得不舒服也可以发消息给我修改。还有下述中,对象代指json的1个层级,而不是整体。的概念在函数中也可以知道,就是官方用来做健值的预定义用到,当然案例2中就是直接添加的函数,越过了项。

/***** 构成案例1 *****/
/*** 创建 ***/
(cJSON *) cJSON_CreateObject();			// 创建对象(1层json对象)
(cJSON *) cJSON_CreateArray();			// 创建数组
(cJSON *) cJSON_CreateString("str");	// 创建字符串,返回cJSON*对象
(cJSON *) cJSON_CreateNumber(12345);	// 创建双浮点型,返回cJSON*对象
/*** 添加 ***/
(cJSON_bool) cJSON_AddItemToArray(array,item);				// 添加项到数组中
(cJSON_bool) cJSON_AddItemToObject(object, "name", name);	// 添加项到对象中
/***** 构成案例2 *****/
/*** 添加和添加 ***/
(cJSON*) cJSON_AddArrayToObject(object, "Array");		// 为对象添加数组键
(cJSON*) cJSON_AddStringToObject(object, "key", "str");	// 为对象添加键:健值(字符串)
(cJSON*) cJSON_AddNumberToObject(object, "key", 123);	// 为对象添加键:健值(双浮点型)
/***** 共用部分 *****/
/*** 打印与销毁 ***/
(char *) cJSON_Print(object);		// 列出cJSON*结构,返回到char*对象中,供正常打印
(void) cJSON_Delete(object);		// 销毁cJSON*结构(不让内存泄漏)

解析案例

基于官方解析JSON对象的案例来分析,所要解析的JSON就是上述案例构成的。

代码案例1
/* 如果显示器支持全高清,返回1,否则返回0 */
int supports_full_hd(const char * const monitor)
{
    const cJSON *resolution = NULL;
    const cJSON *resolutions = NULL;
    const cJSON *name = NULL;
    int status = 0;
    cJSON *monitor_json = cJSON_Parse(monitor);
    if (monitor_json == NULL)
    {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL)
        {
            fprintf(stderr, "Error before: %s\n", error_ptr);
        }
        status = 0;
        goto end;
    }

    name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
    if (cJSON_IsString(name) && (name->valuestring != NULL))
    {
        printf("Checking monitor \"%s\"\n", name->valuestring);
    }

    resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
    // 笔者:该函数其实是个宏,定义的for函数,用来迭代获取
    cJSON_ArrayForEach(resolution, resolutions)
    {
        cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
        cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");

        if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
        {
            status = 0;
            goto end;
        }

        if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
        {
            status = 1;
            goto end;
        }
    }

end:
    cJSON_Delete(monitor_json);
    return status;
}
解析案例函数
/*** 定位数据 ***/
cJSON_ArrayForEach	// 该函数是宏,定义的是for()所以后续才像函数那样又接了{}
(cJSON *) cJSON_Parse(const char *value);	// 提供一个JSON块(字符串指针),这将返回一个可以查询的cJSON对象
(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);	// 通过对象查询键的值
/*** 获取数据 ***/
/*
if (cJSON_IsString(name) && (name->valuestring != NULL))
{
    printf("Checking monitor \"%s\"\n", name->valuestring);
}
在案例中可以看到官方是这样获取数据的,通过函数判断类型,值指向是否为空,通过指针指向储存类型值获取。
不过我看官方也有直接获取函数不知道为什么没有用。
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
*/
/*** 销毁 ***/
(void) cJSON_Delete(cJSON *item);	// 销毁cJSON*结构(不让内存泄漏)

链接

这里有下载好的cJSON项目,怕大家暂时l连接不上Github,时间是2024/8/7下载的。

通过百度网盘分享的文件:cJSON.rar
链接:https://pan.baidu.com/s/1JHPHrCELqCuXUIjTCJ_Zog  提取码:liam

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cJSON是一个用于在C语言中操作JSON数据的开发库。您可以通过在Linux系统上编译和安装cJSON库来使用它。以下是使用cJSON库创建和操作JSON数据的示例代码: ```c #include <stdio.h> #include "cJSON.h" int main() { cJSON *root = cJSON_CreateObject(); // 创建根节点 cJSON *item = cJSON_CreateObject(); // 创建semantic节点 cJSON *next = cJSON_CreateObject(); // 创建slots节点 cJSON_AddItemToObject(root, "rc", cJSON_CreateNumber(0)); // 在根节点下添加rc节点 cJSON_AddItemToObject(root, "operation", cJSON_CreateString("CALL")); // 在根节点下添加operation节点 cJSON_AddItemToObject(root, "service", cJSON_CreateString("telephone")); // 在根节点下添加service节点 cJSON_AddItemToObject(root, "text", cJSON_CreateString("打电话给张三")); // 在根节点下添加text节点 cJSON_AddItemToObject(root, "semantic", item); // 在根节点下添加semantic节点 cJSON_AddItemToObject(item, "slots", next); // 在semantic节点下添加slots节点 cJSON_AddItemToObject(next, "name", cJSON_CreateString("张三")); // 在slots节点下添加name节点 printf("%s\n", cJSON_Print(root)); // 打印整个JSON字符串 return 0; } ``` 这段代码将创建一个包含您提供的样例JSON数据的JSON对象,并打印出整个JSON字符串。您可以根据您的需求修改和扩展这段代码来操作JSON数据。 请注意,您需要在编译和链接过程中将cJSON库链接到您的项目中。您可以通过克隆cJSON源码并将其添加到您的项目中来完成这一步骤。有关如何在Linux上使用cJSON库的更多信息,请参考cJSON库的文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值