在C语言开发中,处理JSON格式数据是常见需求,cJSON作为轻量高效的JSON解析库被广泛应用,它完全用C语言编写,没有额外的依赖,适合嵌入式和常规C项目使用。

cJSON库的安装
cJSON是开源库,我们可以从官方仓库获取源码进行安装,步骤如下:
- 首先从开源仓库下载cJSON的源码包,解压后得到cJSON.c和cJSON.h两个核心文件
- 如果是Linux系统,可以将这两个文件放到项目目录中,编译时一起参与编译,也可以安装到系统目录:
# 进入解压后的cJSON目录 make sudo make install # 安装后头文件会放到/usr/local/include,库文件放到/usr/local/lib
- 如果是Windows系统,直接将cJSON.c和cJSON.h添加到你的项目工程中即可,编译时会自动处理
cJSON核心数据结构
cJSON库的核心数据结构是cJSON结构体,定义如下:
typedef struct cJSON {
struct cJSON *next; // 下一个节点
struct cJSON *prev; // 上一个节点
struct cJSON *child; // 子节点,用于数组和对象类型
int type; // 节点类型,如cJSON_Number、cJSON_String等
char *valuestring; // 字符串类型的值
int valueint; // 整数类型的值
double valuedouble; // 浮点数类型的值
char *string; // 对象的键名
} cJSON;
常用的类型宏定义包括:cJSON_False、cJSON_True、cJSON_NULL、cJSON_Number、cJSON_String、cJSON_Array、cJSON_Object。
cJSON常用API介绍
解析相关API
cJSON_Parse(const char *value):将JSON字符串解析为cJSON对象,解析失败返回NULLcJSON_GetObjectItem(const cJSON *object, const char *string):从JSON对象中获取指定键名的子节点cJSON_GetArrayItem(const cJSON *array, int index):从JSON数组中获取指定下标的元素cJSON_GetArraySize(const cJSON *array):获取JSON数组的长度
释放相关API
cJSON_Delete(cJSON *c):释放整个cJSON对象的内存,必须调用避免内存泄漏
创建相关API
cJSON_CreateObject():创建一个JSON对象cJSON_CreateArray():创建一个JSON数组cJSON_CreateString(const char *string):创建一个字符串类型的JSON节点cJSON_CreateNumber(double num):创建一个数字类型的JSON节点cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item):向JSON对象中添加键值对cJSON_AddItemToArray(cJSON *array, cJSON *item):向JSON数组中添加元素cJSON_Print(const cJSON *item):将cJSON对象转换为格式化的JSON字符串cJSON_PrintUnformatted(const cJSON *item):将cJSON对象转换为无格式的JSON字符串
解析JSON字符串示例
假设我们要解析如下的JSON字符串:
{
"name": "张三",
"age": 25,
"is_student": false,
"hobbies": ["篮球", "阅读", "编程"],
"address": {
"city": "北京",
"street": "中关村大街"
}
}
解析代码如下:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
// 待解析的JSON字符串
char *json_str = "{"name":"张三","age":25,"is_student":false,"hobbies":["篮球","阅读","编程"],"address":{"city":"北京","street":"中关村大街"}}";
// 解析JSON字符串
cJSON *root = cJSON_Parse(json_str);
if (root == NULL) {
printf("JSON解析失败n");
return -1;
}
// 解析name字段
cJSON *name = cJSON_GetObjectItem(root, "name");
if (name != NULL && name->type == cJSON_String) {
printf("姓名:%sn", name->valuestring);
}
// 解析age字段
cJSON *age = cJSON_GetObjectItem(root, "age");
if (age != NULL && age->type == cJSON_Number) {
printf("年龄:%dn", age->valueint);
}
// 解析is_student字段
cJSON *is_student = cJSON_GetObjectItem(root, "is_student");
if (is_student != NULL && is_student->type == cJSON_False) {
printf("是否学生:否n");
} else if (is_student != NULL && is_student->type == cJSON_True) {
printf("是否学生:是n");
}
// 解析hobbies数组
cJSON *hobbies = cJSON_GetObjectItem(root, "hobbies");
if (hobbies != NULL && hobbies->type == cJSON_Array) {
int size = cJSON_GetArraySize(hobbies);
printf("爱好:");
for (int i = 0; i < size; i++) {
cJSON *hobby = cJSON_GetArrayItem(hobbies, i);
if (hobby != NULL && hobby->type == cJSON_String) {
printf("%s ", hobby->valuestring);
}
}
printf("n");
}
// 解析嵌套的address对象
cJSON *address = cJSON_GetObjectItem(root, "address");
if (address != NULL && address->type == cJSON_Object) {
cJSON *city = cJSON_GetObjectItem(address, "city");
cJSON *street = cJSON_GetObjectItem(address, "street");
if (city != NULL && city->type == cJSON_String && street != NULL && street->type == cJSON_String) {
printf("地址:%s %sn", city->valuestring, street->valuestring);
}
}
// 释放cJSON对象内存
cJSON_Delete(root);
return 0;
}
编译运行上述代码,需要先链接cJSON库,Linux下编译命令为:
gcc test.c -o test -lcjson
创建JSON字符串示例
下面演示如何使用cJSON创建一个JSON对象并转换为字符串:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
// 创建根对象
cJSON *root = cJSON_CreateObject();
// 添加基本类型字段
cJSON_AddItemToObject(root, "name", cJSON_CreateString("李四"));
cJSON_AddItemToObject(root, "age", cJSON_CreateNumber(30));
cJSON_AddItemToObject(root, "is_employed", cJSON_CreateBool(1));
// 创建数组并添加到根对象
cJSON *skills = cJSON_CreateArray();
cJSON_AddItemToArray(skills, cJSON_CreateString("C语言"));
cJSON_AddItemToArray(skills, cJSON_CreateString("Linux"));
cJSON_AddItemToArray(skills, cJSON_CreateString("嵌入式开发"));
cJSON_AddItemToObject(root, "skills", skills);
// 创建嵌套对象并添加到根对象
cJSON *company = cJSON_CreateObject();
cJSON_AddItemToObject(company, "name", cJSON_CreateString("某科技公司"));
cJSON_AddItemToObject(company, "position", cJSON_CreateString("嵌入式工程师"));
cJSON_AddItemToObject(root, "company", company);
// 转换为格式化的JSON字符串
char *json_str = cJSON_Print(root);
printf("生成的JSON字符串:n%sn", json_str);
// 释放内存
free(json_str);
cJSON_Delete(root);
return 0;
}
注意事项
- 每次调用
cJSON_Parse解析得到的cJSON对象,使用完后必须调用cJSON_Delete释放,否则会造成内存泄漏 - 获取节点后要先判断节点类型是否符合预期,避免类型错误导致的程序异常
- 调用
cJSON_Print或cJSON_PrintUnformatted得到的字符串,使用完后需要调用free释放 - 如果项目是多线程环境,需要注意cJSON本身不是线程安全的,多线程操作同一个cJSON对象需要加锁保护