C语言JSON库调用指南:从选择到实践
在C语言开发中,处理JSON数据是常见需求,比如解析API响应、配置文件读取或数据交换,由于C语言本身没有内置JSON支持,开发者通常需要借助第三方库,本文将介绍如何选择合适的C语言JSON库,并以常用的cJSON库为例,详细讲解其调用方法,包括环境搭建、核心API使用及实战示例。
C语言JSON库的选择
目前C语言生态中成熟的JSON库较多,选择时需考虑易用性、性能、功能完整性和维护活跃度,以下是几个主流库的对比:
| 库名 | 特点 | 适用场景 |
|---|---|---|
| cJSON | 轻量级、单文件、无依赖,API简单,支持JSON解析/生成/修改 | 嵌入式、小型项目、快速集成 |
| Jansson | 功能丰富(支持JSON Schema、流式解析),性能较好,文档完善 | 中大型项目、需要高级功能 |
| ujson | 极高性能(基于SIMD优化),支持流式解析,但API相对复杂 | 高性能场景(如实时数据处理) |
| json-c | 老牌库,支持双向转换(JSON↔C对象),但API略显冗长 | 传统项目、C对象映射需求 |
推荐新手首选cJSON:其单文件特性无需额外依赖,API设计直观,适合快速上手,本文以cJSON为例展开讲解。
cJSON库的调用实践
环境搭建
(1)获取源码
cJSON是开源项目,可通过以下方式获取最新源码:
- GitHub仓库:https://github.com/DaveGamble/cJSON
- 直接下载:在仓库页面点击“Code”→“Download ZIP”,解压后得到
cJSON.h(头文件)和cJSON.c(源文件)。
(2)集成到项目
将cJSON.h和cJSON.c添加到你的C语言项目中,在VS Code、Clion或Makefile中配置源文件路径:
# 简单Makefile示例
CC = gcc
CFLAGS = -std=c99 -Wall
TARGET = json_demo
SRCS = cJSON.c main.c
OBJS = $(SRCS:.c=.o)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET)
(3)编译运行
执行make编译,生成可执行文件,若使用命令行直接编译:
gcc cJSON.c main.c -o json_demo -std=c99
cJSON核心API解析
cJSON通过“节点树”结构表示JSON数据,每个节点(cJSON*)可以是对象、数组、字符串、数字等类型,核心API分为解析、遍历、创建、释放四大类。
(1)解析JSON字符串
使用cJSON_Parse()将JSON字符串解析为cJSON对象树:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
const char* json_str = "{\"name\":\"Alice\",\"age\":25,\"is_student\":true,\"courses\":[\"Math\",\"Physics\"]}";
// 解析JSON字符串
cJSON* root = cJSON_Parse(json_str);
if (!root) {
printf("JSON解析失败: %s\n", cJSON_GetErrorPtr());
return 1;
}
// 后续操作...
// 释放内存(重要!)
cJSON_Delete(root);
return 0;
}
注意:cJSON_Parse()返回cJSON*根节点,解析失败时返回NULL,可通过cJSON_GetErrorPtr()获取错误信息。
(2)遍历JSON对象树
根据JSON类型,使用不同API获取数据:
获取对象字段(Object)
假设JSON对象为{"name":"Alice","age":25},获取字段值:
// 获取"name"字段(字符串类型)
cJSON* name_node = cJSON_GetObjectItem(root, "name");
if (cJSON_IsString(name_node)) {
printf("Name: %s\n", name_node->valuestring);
}
// 获取"age"字段(数字类型)
cJSON* age_node = cJSON_GetObjectItem(root, "age");
if (cJSON_IsNumber(age_node)) {
printf("Age: %d\n", age_node->valueint); // 或 age_node->valuedouble
}
遍历数组(Array)
假设JSON数组为["Math","Physics"],遍历元素:
cJSON* courses_node = cJSON_GetObjectItem(root, "courses");
if (cJSON_IsArray(courses_node)) {
int course_count = cJSON_GetArraySize(courses_node);
for (int i = 0; i < course_count; i++) {
cJSON* course = cJSON_GetArrayItem(courses_node, i);
if (cJSON_IsString(course)) {
printf("Course %d: %s\n", i+1, course->valuestring);
}
}
}
获取其他类型
- 布尔值:
cJSON_IsBool(node),通过node->valueint(1=true/0=false)获取。 - 空值:
cJSON_IsNull(node)。
(3)创建JSON数据
除了解析,cJSON也支持动态构建JSON数据,常用API:
创建根节点
cJSON* root = cJSON_CreateObject(); // 创建JSON对象 // 或 cJSON_CreateArray(); // 创建JSON数组
添加字段(对象)
cJSON_AddStringToObject(root, "name", "Bob"); // 添加字符串字段 cJSON_AddNumberToObject(root, "age", 30); // 添加数字字段 cJSON_AddBoolToObject(root, "is_student", false); // 添加布尔字段 cJSON_AddNullToObject(root, "phone"); // 添加空值字段
添加数组元素
cJSON* courses = cJSON_CreateArray();
cJSON_AddItemToArray(courses, cJSON_CreateString("Chemistry"));
cJSON_AddItemToArray(courses, cJSON_CreateString("Biology"));
cJSON_AddItemToObject(root, "courses", courses); // 将数组添加到对象
生成JSON字符串
构建完成后,可通过cJSON_Print()或cJSON_PrintUnformatted()生成字符串:
char* json_str = cJSON_Print(root); // 格式化输出(带缩进)
printf("生成的JSON:\n%s\n", json_str);
char* json_str_unformatted = cJSON_PrintUnformatted(root); // 无格式输出
printf("无格式JSON:\n%s\n", json_str_unformatted);
// 释放字符串内存(cJSON_Print内部malloc)
free(json_str);
free(json_str_unformatted);
(4)释放内存
重要:cJSON解析和创建的内存需手动释放,避免内存泄漏,释放规则:
- 释放根节点会递归释放其所有子节点:
cJSON_Delete(root)。 - 生成JSON字符串后需
free():free(cJSON_Print(root))。
完整示例:解析与生成JSON
以下是一个完整的示例,演示解析JSON字符串、提取数据、修改数据并重新生成JSON:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
int main() {
// 1. 解析JSON字符串
const char* json_str = "{\"name\":\"Alice\",\"age\":25,\"is_student\":true,\"courses\":[\"Math\",\"Physics\"]}";
cJSON* root = cJSON_Parse(json_str);
if (!root) {
printf("JSON解析失败: %s\n", cJSON_GetErrorPtr());
return 1;
}
// 2. 遍历并提取数据
cJSON* name_node = cJSON_GetObjectItem(root, "name");
cJSON* age_node = cJSON_GetObjectItem(root, "age");
cJSON* is_student_node = cJSON_GetObjectItem(root, "is_student");
cJSON* courses_node = cJSON_GetObjectItem(root, "courses");
printf("原始数据:\n");
printf("Name: %s\n", cJSON_IsString(name_node) ? name_node->valuestring : "N/A");
printf("Age: %d\n", cJSON_IsNumber(age_node) ? age_node->valueint : -1);
printf("Is Student: %s\n", cJSON_IsBool(is_student_node) ? (is_student_node->valueint ? "true" : "false") : "N/A");
printf("Courses:\n");
if (cJSON_IsArray(courses_node)) {
int count =


还没有评论,来说两句吧...