在C语言中处理JSON数据:实用指南
JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,因其易读性和跨语言兼容性,已成为现代软件开发中数据存储与传输的主流选择,C语言作为一门接近底层的语言,本身并不内置JSON解析库,开发者需要借助第三方库来处理JSON数据,本文将详细介绍如何在C语言中使用JSON数据,包括常用库的选择、数据解析、构建、读写及错误处理等核心环节。
选择合适的JSON库
在C语言生态中,有多种成熟的JSON库可供选择,以下是几款主流库的特点及适用场景:
cJSON
- 特点:轻量级、单文件实现(仅需
cJSON.h和cJSON.c)、API简单易用,适合嵌入式系统或对资源要求较高的场景。 - 支持功能:JSON解析、构建、遍历、修改及序列化/反序列化。
- GitHub地址:https://github.com/DaveGamble/cJSON
Jansson
- 特点:功能丰富、类型安全、支持UTF-8,提供更完善的错误处理机制,适合复杂JSON场景。
- 依赖:需C99标准支持,部分平台依赖
pkg-config。 - GitHub地址:https://github.com/akheron/jansson
YAJL(Yet Another JSON Library)
- 特点:流式解析(适合大文件)、低内存占用,常用于需要逐块解析JSON的场景(如网络数据流)。
- GitHub地址:https://github.com/lloyd/yajl
ujson
- 特点:高性能,基于SIMD指令优化,适合需要快速解析/生成JSON的高性能场景。
- 限制:API相对复杂,依赖较新的编译器特性。
推荐选择:对于初学者或中小型项目,cJSON是最优选择;若需更健壮的错误处理或流式解析,可考虑Jansson或YAJL,本文以cJSON为例展开讲解。
使用cJSON解析JSON数据
安装与集成
cJSON采用单文件设计,只需下载cJSON.h和cJSON.c,将其添加到项目中即可,若使用CMake,可通过add_subdirectory(cJSON)集成;若使用Makefile,直接编译时包含cJSON.c:
gcc -o demo demo.c cJSON.c -lm
解析JSON字符串
假设有以下JSON字符串,需解析其中的字段:
{
"name": "Alice",
"age": 25,
"isStudent": true,
"courses": ["Math", "Physics"],
"address": {
"city": "Beijing",
"zip": 100000
}
}
示例代码:解析JSON
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
const char *json_str = "{"
"\"name\": \"Alice\","
"\"age\": 25,"
"\"isStudent\": true,"
"\"courses\": [\"Math\", \"Physics\"],"
"\"address\": {"
" \"city\": \"Beijing\","
" \"zip\": 100000"
"}"
"}";
// 1. 解析JSON字符串
cJSON *root = cJSON_Parse(json_str);
if (!root) {
printf("Error parsing JSON: %s\n", cJSON_GetErrorPtr());
return 1;
}
// 2. 获取字符串字段(name)
cJSON *name = cJSON_GetObjectItem(root, "name");
if (cJSON_IsString(name)) {
printf("Name: %s\n", name->valuestring);
}
// 3. 获取数字字段(age)
cJSON *age = cJSON_GetObjectItem(root, "age");
if (cJSON_IsNumber(age)) {
printf("Age: %d\n", age->valueint);
}
// 4. 获取布尔字段(isStudent)
cJSON *is_student = cJSON_GetObjectItem(root, "isStudent");
if (cJSON_IsBool(is_student)) {
printf("Is Student: %s\n", cJSON_IsTrue(is_student) ? "true" : "false");
}
// 5. 获取数组字段(courses)
cJSON *courses = cJSON_GetObjectItem(root, "courses");
if (cJSON_IsArray(courses)) {
printf("Courses: ");
cJSON *course = NULL;
cJSON_ArrayForEach(course, courses) {
if (cJSON_IsString(course)) {
printf("%s ", course->valuestring);
}
}
printf("\n");
}
// 6. 获取嵌套对象(address)
cJSON *address = cJSON_GetObjectItem(root, "address");
if (cJSON_IsObject(address)) {
cJSON *city = cJSON_GetObjectItem(address, "city");
cJSON *zip = cJSON_GetObjectItem(address, "zip");
if (cJSON_IsString(city) && cJSON_IsNumber(zip)) {
printf("Address: %s, %d\n", city->valuestring, zip->valueint);
}
}
// 7. 释放JSON对象(避免内存泄漏)
cJSON_Delete(root);
return 0;
}
关键步骤说明:
cJSON_Parse():将JSON字符串解析为cJSON对象树,失败时返回NULL,可通过cJSON_GetErrorPtr()获取错误信息。cJSON_GetObjectItem():从对象中按key获取cJSON节点,若key不存在则返回NULL。- 类型判断:需通过
cJSON_IsString()、cJSON_IsNumber()等宏确认节点类型,避免直接访问valuestring/valueint导致未定义行为。 cJSON_ArrayForEach():遍历数组节点的便捷宏。cJSON_Delete():释放整个cJSON对象树及其所有子节点,必须调用,否则会导致内存泄漏。
构建JSON数据
除了解析,cJSON还支持动态构建JSON对象,以下示例演示如何构建与上述示例相同的JSON数据:
示例代码:构建JSON
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
// 1. 创建根对象(JSON对象)
cJSON *root = cJSON_CreateObject();
if (!root) {
printf("Failed to create root object\n");
return 1;
}
// 2. 添加字符串字段(name)
cJSON_AddStringToObject(root, "name", "Alice");
// 3. 添加数字字段(age)
cJSON_AddNumberToObject(root, "age", 25);
// 4. 添加布尔字段(isStudent)
cJSON_AddBoolToObject(root, "isStudent, cJSON_True);
// 5. 添加数组字段(courses)
cJSON *courses = cJSON_CreateArray();
cJSON_AddItemToArray(courses, cJSON_CreateString("Math"));
cJSON_AddItemToArray(courses, cJSON_CreateString("Physics"));
cJSON_AddItemToObject(root, "courses", courses);
// 6. 添加嵌套对象(address)
cJSON *address = cJSON_CreateObject();
cJSON_AddStringToObject(address, "city", "Beijing");
cJSON_AddNumberToObject(address, "zip", 100000);
cJSON_AddItemToObject(root, "address", address);
// 7. 生成JSON字符串(格式化/非格式化)
char *json_str = cJSON_Print(root); // 非格式化(无缩进)
// char *json_str = cJSON_PrintPretty(root); // 格式化(带缩进)
printf("Generated JSON:\n%s\n", json_str);
// 8. 释放内存
free(json_str); // cJSON_Print返回的字符串需手动释放
cJSON_Delete(root);
return 0;
}
关键API说明:
cJSON_CreateObject()/cJSON_CreateArray():创建JSON对象/数组节点。cJSON_AddStringToObject()/cJSON_AddNumberToObject():向对象中添加键值对。cJSON_AddItemToArray():向数组中添加子节点(需先创建子节点)。cJSON_Print()/cJSON_PrintPretty():将cJSON对象序列化为JSON字符串,前者返回紧凑格式,后者返回带缩进的易读格式,返回的字符串需用free()释放。
读写JSON文件
实际开发中,JSON数据常存储在文件中,以下是读写JSON文件的示例:
从文件读取JSON
#include <stdio.h> #include <stdlib.h> #include "cJSON.h" cJSON *load_json_from



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