JSON处理C函数库-cJSON


libcjson是一个用于 JSON 数据编解码的轻量级C函数库,文件只有 500 多行,速度理想。其代码维护良好,结构简单易懂,对于想要学习 C 语言项目或者处理简单 JSON 数据的开发者来说是一个很好的选择。虽然功能不是极其强大,但在很多对性能要求较高且 JSON 操作不特别复杂的场景下非常适用。采用MIT协议授权。
libcjson is an ultralightweight JSON parser in ANSI C. cJSON is written in ANSI C (or C89, C90). If your compiler or C library doesn't follow this standard, correct behavior is not guaranteed.
适用于小型项目或者对资源占用要求严格的系统中,用于 JSON 数据的生成和解析,比如在嵌入式系统中与其他设备进行简单的 JSON 格式数据通信,或者在一些轻量级的应用程序中处理配置文件等。使用uJson库有两种方式:使用编译好的动态库或者静态库;将源码导入到自己工程中一起参与编译,cJson.c和cJson.h。
基本类型
null is created with cJSON_CreateNull,
booleans are created with cJSON_CreateTrue, cJSON_CreateFalse or cJSON_CreateBool,
numbers are created with cJSON_CreateNumber. This will set both valuedouble and valueint. If the number is outside of the range of an integer, INT_MAX or INT_MIN are used for valueint,
strings are created with cJSON_CreateString (copies the string) or with cJSON_CreateStringReference (directly points to the string. This means that valuestring won't be deleted by cJSON_Delete and you are responsible for its lifetime, useful for constants).
另外有Arrays、Objects类型。
由于C语言是强类型语言,任何json中的独立属性对于C实现来说都视为一个独立的对象,然后用指针将这些对象联系起来;具体的话,可以直接阅读cJson.h的函数,都很直观。使用时一定要注意动态内存的释放!尽管json更现代,但是在实际嵌入式平台,如果没有系统内存管理支撑,不建议用c去处理json数据,动态内存分配着实有点令人担心。
克隆代码仓库后在项目文件夹下新建build文件夹,注意这里的编译器要与最终你项目的编译器统一;在build文件夹下执行Cmake生成makefile文件。
cJSON\build>cmake .. -G "Unix Makefiles" -DENABLE_CJSON_TEST=off
也可执行make编译,生成cJson动态库。在build文件夹下生成dll动态库,动态库的特点就是使用的时候不链接的,运行的程序的时候再调用。所以这个dll文件需要放到跟可执行程序相同目录下。其实这个库只有一个cJson.c文件,可以在自己项目中一起编译。
编码示例1
#include <stdio.h>
#include "cJSON.h"
int main() {
// 创建一个JSON对象
cJSON *root = cJSON_CreateObject();
if (root == NULL) {
return 1;
}
// 在JSON对象中添加一个字符串类型的键值对
cJSON_AddItemToObject(root, "name", cJSON_CreateString("John"));
// 将JSON对象转换为字符串
char *json_string = cJSON_Print(root);
if (json_string == NULL) {
cJSON_Delete(root);
return 1;
}
// 打印JSON字符串
printf("%s\n", json_string);
// 释放内存
cJSON_Delete(root);
free(json_string);
return 0;
}
解码示例
#include <stdio.h>
#include "cJSON.h"
int main() {
const char *json_string = "{\"name\":\"John\"}";
// 解析JSON字符串
cJSON *root = cJSON_Parse(json_string);
if (root == NULL) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr!= NULL) {
printf("Error before: %s\n", error_ptr);
}
return 1;
}
// 获取"name"键对应的值
cJSON *name_json = cJSON_GetObjectItem(root, "name");
if (cJSON_IsString(name_json)) {
printf("Name: %s\n", name_json->valuestring);
}
// 释放内存
cJSON_Delete(root);
return 0;
}
编码示例2
封装Json结构并打印我们假定一个json数据结构体:{
"APP_IS_VALID": true,
"REQUEST_UPDATE": false,
"APP_INFO": {
"VERSION": "0.00.001",
"RELEASE_DATE": "2025-05-16",
"SH256": "0123456789abcdef"
},
"CONFIGURATION_TYPE_LIST": ["High","Normal","Low"]
}
build中存放编译相关文件,记得拷贝cJson.dll到build文件夹,在main.c中实现测试。
#include <stdio.h>
#include <stddef.h>
#include "cJson/cJson.h"
#include <stdlib.h>
void demo1(void) {
cJSON *APP_INFO = cJSON_CreateObject();
cJSON_AddItemToObject(APP_INFO, "VERSION", cJSON_CreateString("0.00.001"));
cJSON_AddItemToObject(APP_INFO, "RELEASE_DATE", cJSON_CreateString("2025-05-16"));
cJSON_AddItemToObject(APP_INFO, "SH256", cJSON_CreateString("0123456789abcdef"));
cJSON* CONFIGURATION_TYPE_LIST = cJSON_CreateArray();
cJSON_AddItemToArray(CONFIGURATION_TYPE_LIST, cJSON_CreateString("High"));
cJSON_AddItemToArray(CONFIGURATION_TYPE_LIST, cJSON_CreateString("Normal"));
cJSON_AddItemToArray(CONFIGURATION_TYPE_LIST, cJSON_CreateString("Low"));
cJSON* GLOBAL_CFG = cJSON_CreateObject();
cJSON_AddItemToObject(GLOBAL_CFG, "APP_IS_VALID", cJSON_CreateBool(0));
cJSON_AddItemToObject(GLOBAL_CFG, "REQUEST_UPDATE", cJSON_CreateBool(0));
cJSON_AddItemToObject(GLOBAL_CFG, "APP_INFO", APP_INFO);
cJSON_AddItemToObject(GLOBAL_CFG, "CONFIGURATION_TYPE_LIST", CONFIGURATION_TYPE_LIST);
char *cPrint = cJSON_Print(GLOBAL_CFG);
char *cPrintUnformatted = cJSON_PrintUnformatted(GLOBAL_CFG);
printf("cJSON_Print:\n%s\n", cPrint);
printf("cJSON_PrintUnformatted:\n%s\n", cPrintUnformatted);
// 记得使用cJSON_Print 和 cJSON_PrintUnformatted返回来的字符指针需要free掉内存!
free(cPrint);
free(cPrintUnformatted);
}
int main(void) {
demo1();
}
编译通过后直接执行可以看到结果。
解析Json文件并获取属性
解析时从严谨和安全角度,需要使用结构体中的type类型进行判断,再取数据或者对象;可以使用cJSON_Print函数去获取字符串,也可以使用结构体中的valuestring取值,但要注意的是,使用cJSON_Print函数去获取字符串之后需要free掉获取到的指针,否则会造成内存泄漏。
#include <string.h>
#include <sys/stat.h>
#include <stdbool.h>
void demo2() {
/* open json file*/
FILE *file = NULL;
file = fopen("../cfg.json", "r");
if (file == NULL) {
printf("Open file failed!\n");
return;
}
/* fetch file's size */
struct stat statBuffer;
stat("../cfg.json", &statBuffer);
int fileSize = statBuffer.st_size;
/* malloc memory*/
char *jsonStr = (char *)malloc(sizeof(char) * fileSize + 1);
memset(jsonStr, 0, fileSize + 1);
/* read string */
int size = fread(jsonStr, sizeof(char), fileSize, file);
if (size == 0) {
printf("Read file Failed!\n");
fclose(file);
return;
}
printf("%s\n", jsonStr);
fclose(file);
/* parser string to jsonString*/
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
free(jsonStr);
return;
}
free(jsonStr);
cJSON *item = NULL;
char *v_str = NULL;
double v_double = 0.0;
int v_int = 0;
bool v_bool = false;
/* 获取APP_INFO对象 */
item = cJSON_GetObjectItem(root, "APP_INFO");
if (item != NULL) {
/* 判断是否是新的json对象 */
if (item->type == cJSON_Object) {
cJSON* version = NULL;
/* 获取VERSION对象 */
version = cJSON_GetObjectItem(item, "VERSION");
if (version->type == cJSON_String) {
v_str = version->valuestring;
printf("VERSION = %s\n", v_str);
}
}
}
}
int main(void) {
demo2();
}
在上面的示例中,先从cfg.json文件中一次性读取所有的字符信息,然后将字符一次性转换成jsonString然后解析。这里以获取APP的版本号为例。
最新版本:1.7
v1.7.8于2024年5月发布。
项目主页:https://github.com/DaveGamble/cJSON
libcjson is an ultralightweight JSON parser in ANSI C. cJSON is written in ANSI C (or C89, C90). If your compiler or C library doesn't follow this standard, correct behavior is not guaranteed.
适用于小型项目或者对资源占用要求严格的系统中,用于 JSON 数据的生成和解析,比如在嵌入式系统中与其他设备进行简单的 JSON 格式数据通信,或者在一些轻量级的应用程序中处理配置文件等。使用uJson库有两种方式:使用编译好的动态库或者静态库;将源码导入到自己工程中一起参与编译,cJson.c和cJson.h。
基本类型
null is created with cJSON_CreateNull,
booleans are created with cJSON_CreateTrue, cJSON_CreateFalse or cJSON_CreateBool,
numbers are created with cJSON_CreateNumber. This will set both valuedouble and valueint. If the number is outside of the range of an integer, INT_MAX or INT_MIN are used for valueint,
strings are created with cJSON_CreateString (copies the string) or with cJSON_CreateStringReference (directly points to the string. This means that valuestring won't be deleted by cJSON_Delete and you are responsible for its lifetime, useful for constants).
另外有Arrays、Objects类型。
由于C语言是强类型语言,任何json中的独立属性对于C实现来说都视为一个独立的对象,然后用指针将这些对象联系起来;具体的话,可以直接阅读cJson.h的函数,都很直观。使用时一定要注意动态内存的释放!尽管json更现代,但是在实际嵌入式平台,如果没有系统内存管理支撑,不建议用c去处理json数据,动态内存分配着实有点令人担心。
克隆代码仓库后在项目文件夹下新建build文件夹,注意这里的编译器要与最终你项目的编译器统一;在build文件夹下执行Cmake生成makefile文件。
cJSON\build>cmake .. -G "Unix Makefiles" -DENABLE_CJSON_TEST=off
也可执行make编译,生成cJson动态库。在build文件夹下生成dll动态库,动态库的特点就是使用的时候不链接的,运行的程序的时候再调用。所以这个dll文件需要放到跟可执行程序相同目录下。其实这个库只有一个cJson.c文件,可以在自己项目中一起编译。
编码示例1
#include <stdio.h>
#include "cJSON.h"
int main() {
// 创建一个JSON对象
cJSON *root = cJSON_CreateObject();
if (root == NULL) {
return 1;
}
// 在JSON对象中添加一个字符串类型的键值对
cJSON_AddItemToObject(root, "name", cJSON_CreateString("John"));
// 将JSON对象转换为字符串
char *json_string = cJSON_Print(root);
if (json_string == NULL) {
cJSON_Delete(root);
return 1;
}
// 打印JSON字符串
printf("%s\n", json_string);
// 释放内存
cJSON_Delete(root);
free(json_string);
return 0;
}
解码示例
#include <stdio.h>
#include "cJSON.h"
int main() {
const char *json_string = "{\"name\":\"John\"}";
// 解析JSON字符串
cJSON *root = cJSON_Parse(json_string);
if (root == NULL) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr!= NULL) {
printf("Error before: %s\n", error_ptr);
}
return 1;
}
// 获取"name"键对应的值
cJSON *name_json = cJSON_GetObjectItem(root, "name");
if (cJSON_IsString(name_json)) {
printf("Name: %s\n", name_json->valuestring);
}
// 释放内存
cJSON_Delete(root);
return 0;
}
编码示例2
封装Json结构并打印我们假定一个json数据结构体:{
"APP_IS_VALID": true,
"REQUEST_UPDATE": false,
"APP_INFO": {
"VERSION": "0.00.001",
"RELEASE_DATE": "2025-05-16",
"SH256": "0123456789abcdef"
},
"CONFIGURATION_TYPE_LIST": ["High","Normal","Low"]
}
build中存放编译相关文件,记得拷贝cJson.dll到build文件夹,在main.c中实现测试。
#include <stdio.h>
#include <stddef.h>
#include "cJson/cJson.h"
#include <stdlib.h>
void demo1(void) {
cJSON *APP_INFO = cJSON_CreateObject();
cJSON_AddItemToObject(APP_INFO, "VERSION", cJSON_CreateString("0.00.001"));
cJSON_AddItemToObject(APP_INFO, "RELEASE_DATE", cJSON_CreateString("2025-05-16"));
cJSON_AddItemToObject(APP_INFO, "SH256", cJSON_CreateString("0123456789abcdef"));
cJSON* CONFIGURATION_TYPE_LIST = cJSON_CreateArray();
cJSON_AddItemToArray(CONFIGURATION_TYPE_LIST, cJSON_CreateString("High"));
cJSON_AddItemToArray(CONFIGURATION_TYPE_LIST, cJSON_CreateString("Normal"));
cJSON_AddItemToArray(CONFIGURATION_TYPE_LIST, cJSON_CreateString("Low"));
cJSON* GLOBAL_CFG = cJSON_CreateObject();
cJSON_AddItemToObject(GLOBAL_CFG, "APP_IS_VALID", cJSON_CreateBool(0));
cJSON_AddItemToObject(GLOBAL_CFG, "REQUEST_UPDATE", cJSON_CreateBool(0));
cJSON_AddItemToObject(GLOBAL_CFG, "APP_INFO", APP_INFO);
cJSON_AddItemToObject(GLOBAL_CFG, "CONFIGURATION_TYPE_LIST", CONFIGURATION_TYPE_LIST);
char *cPrint = cJSON_Print(GLOBAL_CFG);
char *cPrintUnformatted = cJSON_PrintUnformatted(GLOBAL_CFG);
printf("cJSON_Print:\n%s\n", cPrint);
printf("cJSON_PrintUnformatted:\n%s\n", cPrintUnformatted);
// 记得使用cJSON_Print 和 cJSON_PrintUnformatted返回来的字符指针需要free掉内存!
free(cPrint);
free(cPrintUnformatted);
}
int main(void) {
demo1();
}
编译通过后直接执行可以看到结果。
解析Json文件并获取属性
解析时从严谨和安全角度,需要使用结构体中的type类型进行判断,再取数据或者对象;可以使用cJSON_Print函数去获取字符串,也可以使用结构体中的valuestring取值,但要注意的是,使用cJSON_Print函数去获取字符串之后需要free掉获取到的指针,否则会造成内存泄漏。
#include <string.h>
#include <sys/stat.h>
#include <stdbool.h>
void demo2() {
/* open json file*/
FILE *file = NULL;
file = fopen("../cfg.json", "r");
if (file == NULL) {
printf("Open file failed!\n");
return;
}
/* fetch file's size */
struct stat statBuffer;
stat("../cfg.json", &statBuffer);
int fileSize = statBuffer.st_size;
/* malloc memory*/
char *jsonStr = (char *)malloc(sizeof(char) * fileSize + 1);
memset(jsonStr, 0, fileSize + 1);
/* read string */
int size = fread(jsonStr, sizeof(char), fileSize, file);
if (size == 0) {
printf("Read file Failed!\n");
fclose(file);
return;
}
printf("%s\n", jsonStr);
fclose(file);
/* parser string to jsonString*/
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
free(jsonStr);
return;
}
free(jsonStr);
cJSON *item = NULL;
char *v_str = NULL;
double v_double = 0.0;
int v_int = 0;
bool v_bool = false;
/* 获取APP_INFO对象 */
item = cJSON_GetObjectItem(root, "APP_INFO");
if (item != NULL) {
/* 判断是否是新的json对象 */
if (item->type == cJSON_Object) {
cJSON* version = NULL;
/* 获取VERSION对象 */
version = cJSON_GetObjectItem(item, "VERSION");
if (version->type == cJSON_String) {
v_str = version->valuestring;
printf("VERSION = %s\n", v_str);
}
}
}
}
int main(void) {
demo2();
}
在上面的示例中,先从cfg.json文件中一次性读取所有的字符信息,然后将字符一次性转换成jsonString然后解析。这里以获取APP的版本号为例。
最新版本:1.7
v1.7.8于2024年5月发布。
项目主页:https://github.com/DaveGamble/cJSON