在C语言中使用JSON数据格式:从入门到实践
JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,因其易读、易解析的特性,已成为现代软件开发中数据交互的主流选择,C语言作为一门接近底层的系统编程语言,本身并未内置JSON支持,如何在C语言中高效处理JSON数据呢?本文将介绍常用的JSON库、数据解析与生成方法,并通过实例展示完整的使用流程。
选择合适的JSON库
在C语言中处理JSON,通常依赖第三方库,以下是几款主流库的对比,可根据需求选择:
cJSON
- 特点:轻量级、单文件(仅
cJSON.h和cJSON.c)、无依赖、API简单易用。 - 适用场景:嵌入式系统、小型项目,对内存和依赖敏感的场景。
- GitHub地址:https://github.com/DaveGamble/cJSON
Jansson
- 特点:功能丰富(支持JSON标准全特性)、类型安全、提供迭代器接口。
- 适用场景:中大型项目,需要复杂JSON操作(如流式解析、动态类型处理)。
- 官网:https://github.com/akheron/jansson
yajl (Yet Another JSON Library)
- 特点:高性能、支持流式解析(适合大文件或网络数据)、绑定多种语言。
- 适用场景:需要处理大规模JSON数据或实时数据流(如API响应解析)。
- 官网:https://github.com/lloyd/yajl
本文以cJSON为例,因其简单易学,适合快速上手。
安装与配置cJSON
源码编译
从GitHub克隆cJSON仓库,或直接下载cJSON.h和cJSON.c文件,将其放入项目中。
集成到项目
-
GCC编译:
gcc your_program.c cJSON.c -o your_program -lm
(注意:
-lm链接数学库,部分操作可能需要) -
CMake集成(推荐):
在CMakeLists.txt中添加:add_executable(your_program your_program.c cJSON.c)
解析JSON数据
JSON数据的核心结构包括对象(Object)、数组(Array)、字符串(String)、数字(Number)、布尔值(Boolean)和NULL,cJSON通过链表结构表示这些对象,每个节点(cJSON*)包含类型和值信息。
解析JSON字符串
使用cJSON_Parse()函数解析JSON字符串,返回根节点指针:
#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* name = cJSON_GetObjectItem(root, "name");
cJSON* age = cJSON_GetObjectItem(root, "age");
cJSON* is_student = cJSON_GetObjectItem(root, "is_student");
cJSON* courses = cJSON_GetObjectItem(root, "courses");
printf("Name: %s\n", name->valuestring); // 字符串
printf("Age: %d\n", age->valueint); // 整数(注意:JSON数字可能是浮点数,需用`cJSON_IsNumber()`判断)
printf("Is Student: %s\n", is_student->valueint ? "true" : "false"); // 布尔值
// 解析数组
printf("Courses: ");
cJSON* course = NULL;
cJSON_ArrayForEach(course, courses) {
printf("%s ", course->valuestring);
}
printf("\n");
// 释放内存(重要!)
cJSON_Delete(root);
return 0;
}
输出:
Name: Alice
Age: 25
Is Student: true
Courses: Math Physics
处理复杂嵌套结构
假设JSON包含嵌套对象和数组:
{
"user": {
"id": 101,
"profile": {"city":"Beijing","hobby":["Reading","Coding"]}
},
"status": "active"
}
解析代码:
cJSON* root = cJSON_Parse(nested_json_str);
cJSON* user = cJSON_GetObjectItem(root, "user");
cJSON* id = cJSON_GetObjectItem(user, "id");
cJSON* profile = cJSON_GetObjectItem(user, "profile");
cJSON* city = cJSON_GetObjectItem(profile, "city");
printf("User ID: %d, City: %s\n", id->valueint, city->valuestring);
生成JSON数据
cJSON提供了cJSON_CreateXXX系列函数构建JSON节点,并通过cJSON_AddItemToObject或cJSON_AddItemToArray组合成完整结构。
构建简单JSON
#include "cJSON.h"
int main() {
// 创建根对象
cJSON* root = cJSON_CreateObject();
// 添加键值对
cJSON_AddStringToObject(root, "name", "Bob");
cJSON_AddNumberToObject(root, "age", 30);
cJSON_AddBoolToObject(root, "is_married", 0);
// 创建数组并添加到对象
cJSON* courses = cJSON_CreateArray();
cJSON_AddItemToArray(courses, cJSON_CreateString("History"));
cJSON_AddItemToArray(courses, cJSON_CreateString("Art"));
cJSON_AddItemToObject(root, "courses", courses);
// 生成JSON字符串(格式化输出)
char* json_str = cJSON_Print(root);
printf("Generated JSON:\n%s\n", json_str);
// 释放内存
free(json_str); // cJSON_Print返回的字符串需手动释放
cJSON_Delete(root);
return 0;
}
输出:
{
"name": "Bob",
"age": 30,
"is_married": false,
"courses": [
"History",
"Art"
]
}
生成嵌套JSON
cJSON* root = cJSON_CreateObject(); cJSON* user = cJSON_CreateObject(); cJSON_AddNumberToObject(user, "id", 102); cJSON_AddStringToObject(user, "name", "Charlie"); cJSON_AddItemToObject(root, "user", user);
错误处理与内存管理
错误处理
- 解析失败:
cJSON_Parse返回NULL,可通过cJSON_GetErrorPtr()获取错误位置:if (!root) { fprintf(stderr, "JSON解析错误: %s\n", cJSON_GetErrorPtr()); return 1; } - 类型不匹配:使用
cJSON_IsString()、cJSON_IsNumber()等函数检查节点类型,避免直接访问未定义字段:if (cJSON_IsNumber(age)) { printf("Age: %d\n", age->valueint); }
内存管理
- 释放资源:
cJSON_Delete(root)会递归释放所有子节点,避免内存泄漏。 - 字符串释放:
cJSON_Print()和cJSON_PrintUnformatted()返回的动态分配字符串需用free()释放。
实战案例:解析网络API响应
假设从HTTP API获取以下JSON响应(模拟):
{
"code": 200,
"message": "Success",
"data": {
"total": 2,
"items": [
{"id": 1, "name": "Item A", "price": 10.99},
{"id": 2, "name": "Item B", "price": 20.50}
]
}
}
解析代码:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
void parse_api_response(const char* json_str) {
cJSON* root = cJSON_Parse(json_str);
if (!root) {
printf("API响应解析失败\n");
return;
}
// 检查状态码
cJSON* code = cJSON_GetObjectItem(root, "code");
if (code->valueint != 200) {
cJSON* msg = cJSON_GetObjectItem(root, "message");
printf("API错误: %s\n", msg->valuestring);
cJSON_Delete(root);
return;
}
// 提取数据
cJSON* data = cJSON_Get


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