C语言中如何编写JSON:从基础到实践
在C语言中处理JSON数据是许多开发场景(如嵌入式系统、后端服务、跨平台通信)的常见需求,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,以其简洁性和可读性被广泛应用,C语言本身没有内置的JSON支持,因此我们需要借助第三方库或手动解析/生成JSON,本文将详细介绍在C语言中编写JSON的多种方法,包括手动实现、使用第三方库(如cJSON、Jansson)以及最佳实践,帮助开发者根据实际需求选择合适的方案。
JSON基础与C语言的适配性
JSON数据主要由两种结构组成:对象(Object)(无序键值对集合,用包围)和数组(Array)(有序值列表,用[]包围),值(Value)可以是字符串、数字、布尔值、null、对象或数组。
{
"name": "Alice",
"age": 30,
"isStudent": false,
"courses": ["Math", "Physics"],
"address": {
"city": "New York",
"zip": 10001
}
}
C语言是过程式语言,没有原生的JSON类型,但可以通过以下方式映射JSON结构:
- 对象 → 结构体(
struct)或键值对数组(如struct key_value数组); - 数组 → 固定大小数组或动态数组(如
动态数组); - 字符串 →
char*或char[]; - 数字 →
int、float、double等; - 布尔值 →
bool(需<stdbool.h>); null→NULL指针或特殊标记值。
这种映射关系是手动实现或使用库的基础。
手动编写JSON:直接拼接字符串
对于极简单的JSON生成需求(如仅需输出固定结构的JSON),可以直接通过字符串拼接的方式手动编写,这种方法无需依赖第三方库,但缺点是可维护性差、易出错(如未处理转义字符、格式混乱),且无法动态构建复杂JSON。
示例:生成简单的用户信息JSON
#include <stdio.h>
#include <string.h>
int main() {
char name[] = "Bob";
int age = 25;
char city[] = "London";
// 直接拼接JSON字符串
char json[256];
snprintf(json, sizeof(json),
"{\"name\": \"%s\", \"age\": %d, \"city\": \"%s\"}",
name, age, city);
printf("%s\n", json);
return 0;
}
输出:
{"name": "Bob", "age": 25, "city": "London"}
注意事项:
- 字符串转义:JSON中字符串需包含双引号,且内部的双引号需转义为
\",例如"He said: \"Hello\"",手动拼接时需用\"转义,否则会导致JSON格式错误。 - 格式控制:手动拼接难以保证缩进和换行,可读性差;若需格式化输出,需额外处理空格和换行符。
- :若JSON结构或内容动态变化(如字段数量可变),手动拼接会变得非常复杂,难以维护。
使用第三方库:cJSON(轻量级、易用)
cJSON是一个广泛使用的C语言JSON库,由Dave Gamble开发,具有轻量级(单文件实现)、无依赖、API简单等特点,它支持JSON的解析(Parse)、生成(Generate)、修改(Modify)和遍历(Traverse),适合嵌入式系统和资源受限环境。
安装cJSON
cJSON是单文件库,只需下载cJSON.c和cJSON.h即可使用,也可通过包管理器安装(如Ubuntu:sudo apt-get install libcjson-dev)。
核心API
cJSON* cJSON_CreateObject():创建JSON对象。cJSON* cJSON_CreateArray():创建JSON数组。void cJSON_AddStringToObject(cJSON* object, const char* name, const char* value):向对象添加字符串字段。void cJSON_AddNumberToObject(cJSON* object, const char* name, double number):向对象添加数字字段。void cJSON_AddBoolToObject(cJSON* object, const char* name, bool boolean):向对象添加布尔字段。char* cJSON_Print(cJSON* item):生成JSON字符串(无格式化)。char* cJSON_PrintUnformatted(cJSON* item):生成无缩进的JSON字符串(紧凑格式)。void cJSON_Delete(cJSON* item):释放JSON对象内存(必须调用,避免内存泄漏)。
示例:使用cJSON生成复杂JSON
以下代码生成包含对象、数组、嵌套结构的JSON:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
int main() {
// 创建根对象
cJSON* root = cJSON_CreateObject();
// 添加基本字段
cJSON_AddStringToObject(root, "name", "Alice");
cJSON_AddNumberToObject(root, "age", 30);
cJSON_AddBoolToObject(root, "isStudent", false);
// 添加数组字段
cJSON* courses = cJSON_CreateArray();
cJSON_AddItemToArray(courses, cJSON_CreateString("Math"));
cJSON_AddItemToArray(courses, cJSON_CreateString("Physics"));
cJSON_AddItemToObject(root, "courses", courses);
// 添加嵌套对象
cJSON* address = cJSON_CreateObject();
cJSON_AddStringToObject(address, "city", "New York");
cJSON_AddNumberToObject(address, "zip", 10001);
cJSON_AddItemToObject(root, "address", address);
// 生成JSON字符串(格式化输出)
char* json_str = cJSON_Print(root);
printf("%s\n", json_str);
// 释放内存
free(json_str);
cJSON_Delete(root);
return 0;
}
输出:
{
"name": "Alice",
"age": 30,
"isStudent": false,
"courses": [
"Math",
"Physics"
],
"address": {
"city": "New York",
"zip": 10001
}
}
修改和遍历JSON
cJSON也支持修改已生成的JSON,修改age字段并遍历所有字段:
// 修改age字段
cJSON* age_item = cJSON_GetObjectItem(root, "age");
if (age_item) {
age_item->valuedouble = 31; // 数字字段通过valuedouble修改
age_item->valueint = 31; // 整数字段通过valueint修改
}
// 遍历对象字段(需cJSON_ArrayForEach,需包含cJSON_Utils.h)
#include "cJSON_Utils.h"
cJSON* item = NULL;
cJSON_ArrayForEach(item, root) {
printf("Key: %s, Type: %d\n", item->string, item->type);
}
注意事项
- 内存管理:
cJSON_Print返回的字符串需要free释放,cJSON_Delete会递归释放JSON对象及其所有子项,避免内存泄漏。 - 错误处理:cJSON函数返回
NULL通常表示内存分配失败或JSON格式错误,使用时需检查返回值(如cJSON_Parse解析JSON时需判断是否成功)。 - 线程安全:cJSON本身不是线程安全的,若多线程使用需加锁保护。
使用第三方库:Jansson(功能更强大)
Jansson是另一个流行的C语言JSON库,由IBM开发,功能比cJSON更丰富,支持:
- 更严格的JSON规范(如数字精度处理、Unicode转义);
- 流式解析(适合大文件);
- 更完善的错误处理(通过
json_error_t结构体返回错误信息); - 支持JSON与C类型之间的直接转换(如
json_pack、json_unpack)。
安装Jansson
可通过包管理器安装(如Ubuntu:sudo apt-get install libjansson-dev)或从源码编译。
核心API
json_t* json_object():创建JSON对象。json_t* json_array():创建JSON数组。int json_object_set_new(json_t* object, const char* key, json_t* value):向对象添加字段(转移value的所有权)。char* json_dumps(const json_t* object, size_t flags):生成JSON字符串(支持格式化,如JSON_INDENT(4))。void json_decref(json_t* object):释放JSON对象(引用计数管理)。- `json_t



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