cJSON 基础示例

功能说明

演示如何使用 cJSON 库进行 JSON 数据的创建、序列化和解析操作。本示例展示了 cJSON 的基本 API 使用方法,包括创建 JSON 对象、添加不同类型的数据、将对象转换为字符串、解析 JSON 字符串以及提取数据。

硬件连接

无需外部连接,cJSON 为纯软件 JSON 解析库。

示例内容

  1. 创建 JSON 对象并添加字符串、数字和布尔值

  2. 创建嵌套 JSON 对象

  3. 将 JSON 对象转换为字符串格式

  4. 解析 JSON 字符串

  5. 从解析后的 JSON 对象中提取数据

  6. 释放 JSON 对象和字符串内存

编译

重要提示:编译前需要先确认当前示例支持的目标板型,然后将板型标识传给 -DBOARD。请按以下方式选择:

  1. 确认示例限制:查看当前示例 README 中的硬件连接和注意事项,确认是否限定板型。

  2. 参考示例配置:查看相关示例目录下的 sample.yaml,确认支持的板型。

  3. 填写板型标识:SDK 内置板型的标识为 boards/ 下的目录名。例如实际使用的板型目录为 boards/<板型名称>/,则编译参数填写为 -DBOARD=<板型名称>

在 SDK 根目录执行编译,并将命令中的 <示例路径><板型名称> 替换为实际值。

Linux 使用 build.sh

# 通用命令
./build.sh -C -S samples/<示例路径> -DBOARD=<板型名称>

# 示例:使用 arcs_evb 开发板
./build.sh -C -S samples/<示例路径> -DBOARD=arcs_evb

Windows PowerShell 使用 build.ps1

# 通用命令
.\build.ps1 -C -S samples/<示例路径> -DBOARD=<板型名称>

# 示例:使用 arcs_evb 开发板
.\build.ps1 -C -S samples/<示例路径> -DBOARD=arcs_evb

Note

确保已安装对应平台的工具链和 ListenAI 开发工具包。Windows 环境请先执行 .\env.ps1 或直接使用 .\build.ps1 自动加载环境。

注意事项-DBOARD 填写的是板型标识,不是芯片系列名称。如果示例有板型专用配置或额外编译参数,以示例 README 中的说明为准。

烧录

编译完成后,使用 SDK tools/burn 目录下的 cskburn 工具烧录固件。请先根据目标板型和当前示例确定芯片系列、串口设备、烧录地址和固件路径。

Linux:

# 通用命令
./tools/burn/cskburn -C <芯片系列> -s <串口设备> -b 3000000 <烧录地址> <固件路径>

# 示例:使用 arcs_evb 开发板
./tools/burn/cskburn -s /dev/ttyUSB0 -b 3000000 0x0 build/arcs.bin -C arcs

Windows PowerShell:

# 通用命令
.\tools\burn\cskburn.exe -C <芯片系列> -s <串口号> -b 3000000 <烧录地址> <固件路径>

# 示例:使用 arcs_evb 开发板
.\tools\burn\cskburn.exe -C arcs -s COM7 -b 3000000 0x0 .\build\arcs.bin

Note

烧录参数说明

  • -s /dev/ttyUSB0 / -s COM7:串口设备路径,需要根据实际情况修改 - Linux 系统:通常是 /dev/ttyUSB0/dev/ttyACM0 - 可通过 ls /dev/tty* 命令查看可用串口设备 - Windows 系统:通常是 COM7COM8 等,可在“设备管理器”的“端口”中查看 - 不同开发板或 USB 转串口芯片可能使用不同的设备名

  • -b 3000000:烧录波特率(3Mbps)

  • 0x0:烧录起始地址

  • build/arcs.bin / .\build\arcs.bin:编译生成的固件路径

  • -C arcs:芯片类型

注意事项

  • 确保开发板已正确连接到电脑

  • 如果无法识别串口设备,请检查 USB 连接线是否正常,或尝试其他 USB 端口

预期输出

********Arcs SDK 0.1.0 @ v0.0.23.temp.docs-96-gf56c5084660d********
Running on hart-id: 1
I/elog            [1034:42:44.159 1 elog_async] EasyLogger V2.2.99 is initialize success.
this is a cjson samples
Generated JSON:
{
	"name":	"John Doe",
	"age":	30,
	"is_student":	false,
	"info":	{
		"address":	"123 Main St",
		"zip_code":	12345
	}
}
Parsed JSON:
Name: John Doe
Age: 30
Is Student: false
Address: 123 Main St
Zip Code: 12345

说明

  • 输出开头包含系统启动信息和日志系统初始化信息

  • 由于默认启用了自定义内存分配器(CONFIG_CJSON_CUSTOM_INCLUDE=y),输出中会显示内存分配和释放的调试信息(cjson_custom_malloccjson_custom_realloccjson_custom_free

  • 这些调试信息可以帮助了解 cJSON 库的内存使用情况

核心 API

API

说明

cJSON_CreateObject()

创建 JSON 对象

cJSON_AddStringToObject()

向对象添加字符串值

cJSON_AddNumberToObject()

向对象添加数字值

cJSON_AddBoolToObject()

向对象添加布尔值

cJSON_AddItemToObject()

向对象添加子项(如嵌套对象)

cJSON_Print()

将 JSON 对象转换为格式化的字符串

cJSON_Parse()

解析 JSON 字符串为 JSON 对象

cJSON_GetObjectItem()

从对象中获取指定键的项

cJSON_Delete()

删除 JSON 对象并释放内存

关键代码

/* 创建 JSON 对象 */
cJSON *root = cJSON_CreateObject();
cJSON *info = cJSON_CreateObject();

/* 添加数据到 JSON 对象 */
cJSON_AddStringToObject(root, "name", "John Doe");
cJSON_AddNumberToObject(root, "age", 30);
cJSON_AddBoolToObject(root, "is_student", 0);
cJSON_AddItemToObject(root, "info", info);
cJSON_AddStringToObject(info, "address", "123 Main St");
cJSON_AddNumberToObject(info, "zip_code", 12345);

/* 将 JSON 对象转换为字符串 */
char *json_string = cJSON_Print(root);
if (json_string == NULL) {
    fprintf(stderr, "Failed to print JSON.\n");
    cJSON_Delete(root);
    return 1;
}

/* 解析 JSON 字符串 */
cJSON *parsed_root = cJSON_Parse(json_string);
if (parsed_root == NULL) {
    fprintf(stderr, "Failed to parse JSON.\n");
    free(json_string);
    cJSON_Delete(root);
    return 1;
}

/* 提取数据 */
cJSON *name = cJSON_GetObjectItem(parsed_root, "name");
cJSON *age = cJSON_GetObjectItem(parsed_root, "age");
cJSON *parsed_info = cJSON_GetObjectItem(parsed_root, "info");
cJSON *address = cJSON_GetObjectItem(parsed_info, "address");

/* 访问数据 */
printf("Name: %s\n", name->valuestring);
printf("Age: %d\n", age->valueint);

/* 释放内存 */
free(json_string);
cJSON_Delete(root);
cJSON_Delete(parsed_root);

配置说明

自定义内存分配器

本示例支持使用自定义内存分配器,通过以下配置启用:

  • CONFIG_CJSON_CUSTOM_INCLUDE: 启用自定义内存分配器

  • CONFIG_CJSON_CUSTOM_INCLUDE_PATH: 自定义头文件路径(默认:"cjson_custom.h"

启用后,cJSON 将使用 cjson_custom.c 中定义的内存分配函数(cjson_custom_malloccjson_custom_freecjson_custom_realloc)替代标准库的 mallocfreerealloc

注意事项

  1. 内存管理: 使用 cJSON_Print() 返回的字符串必须使用 free() 释放,使用 cJSON_Create*() 创建的对象必须使用 cJSON_Delete() 释放

  2. 返回值检查: cJSON_Print()cJSON_Parse() 可能返回 NULL,使用前必须检查返回值

  3. 嵌套对象: 使用 cJSON_AddItemToObject() 添加嵌套对象时,子对象会在父对象删除时自动删除,无需单独删除

  4. 数据访问: 从 cJSON_GetObjectItem() 获取的指针可能为 NULL(例如键不存在时),访问前必须检查指针有效性,否则可能导致程序崩溃

  5. 字符串访问: 访问 cJSON 对象的字符串值时,使用 item->valuestring。访问数字时,优先使用 cJSON_GetNumberValue()item->valuedouble;注意 item->valueint 已被标记为废弃(DEPRECATED),不推荐使用

  6. 线程安全: cJSON 库本身不是线程安全的,在多线程环境中使用时需要额外的同步机制