在C语言中生成JSON字符串的实用指南
在C语言中处理JSON数据曾是一件相对复杂的事,因为C语言本身没有内置JSON数据类型或原生支持,随着轻量级JSON库的出现,开发者可以方便地在C程序中生成、解析和操作JSON字符串,本文将介绍几种主流的C语言JSON库,重点讲解如何使用它们生成JSON字符串,并提供详细的代码示例和实用技巧。
为什么需要专门的JSON库?
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用键值对(Key-Value)结构,易于人阅读和编写,也易于机器解析和生成,C语言作为底层开发语言,没有像JavaScript那样的原生JSON支持,因此需要借助第三方库来处理JSON数据,这些库通常提供了以下功能:
- 定义JSON对象(Object)和数组(Array)
- 添加键值对(字符串、数字、布尔值、null等类型)
- 构建嵌套的JSON结构
- 将内存中的JSON数据序列化为字符串
选择合适的JSON库是第一步,目前C语言中常用的JSON库包括:cJSON、Jansson、Parson等,cJSON因轻量级(单文件实现)、API简单、无需额外依赖,成为开发者最常用的选择。
使用cJSON库生成JSON字符串
cJSON是一个开源的C语言JSON解析器/生成器,由Dave Gamble开发,代码托管在GitHub上,它的核心优势是“单文件实现”——只需将cJSON.h和cJSON.c添加到项目中即可使用,无需链接其他库。
环境准备
首先下载cJSON源码(从GitHub releases获取),将cJSON.h和cJSON.c放在项目目录中,编译时需要链接这两个文件,例如使用gcc编译:
gcc your_program.c cJSON.c -o your_program -lm
cJSON核心API
cJSON通过链表结构表示JSON数据,每个JSON节点(cJSON结构体)可以是对象、数组、字符串、数字等类型,生成JSON字符串的核心步骤包括:
- 创建JSON节点(
cJSON_CreateXXX系列函数) - 向对象/数组添加子节点(
cJSON_AddItemToObject/cJSON_AddItemToArray) - 将JSON结构体序列化为字符串(
cJSON_Print/cJSON_PrintUnformatted)
常用API说明:
| API函数 | 功能 |
|---|---|
cJSON *cJSON_CreateObject() |
创建JSON对象(键值对集合) |
cJSON *cJSON_CreateArray() |
创建JSON数组(有序值集合) |
cJSON *cJSON_CreateString(const char *string) |
创建JSON字符串节点 |
cJSON *cJSON_CreateNumber(double num) |
创建JSON数字节点 |
cJSON *cJSON_CreateTrue()/cJSON_CreateFalse() |
创建布尔值节点(true/false) |
cJSON *cJSON_CreateNull() |
创建null值节点 |
void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) |
向对象添加键值对(string为键名) |
char *cJSON_Print(const cJSON *item) |
将JSON节点格式化为可读字符串(带缩进) |
void cJSON_Delete(cJSON *item) |
释放JSON节点及其子节点内存 |
生成简单JSON字符串
以下是一个生成简单JSON对象(包含字符串、数字、布尔值)的示例:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
// 1. 创建JSON对象
cJSON *root = cJSON_CreateObject();
// 2. 添加键值对
cJSON_AddStringToObject(root, "name", "张三");
cJSON_AddNumberToObject(root, "age", 25);
cJSON_AddBoolToObject(root, "is_student", cJSON_False);
// 3. 序列化为字符串(带缩进,便于阅读)
char *json_string = cJSON_Print(root);
if (json_string) {
printf("生成的JSON字符串:\n%s\n", json_string);
}
// 4. 释放内存(重要!避免内存泄漏)
free(json_string);
cJSON_Delete(root);
return 0;
}
输出结果:
{
"name": "张三",
"age": 25,
"is_student": false
}
生成嵌套JSON结构
JSON支持对象和数组的嵌套,例如生成一个包含数组和嵌套对象的复杂JSON:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
cJSON *root = cJSON_CreateObject();
cJSON *address = cJSON_CreateObject();
cJSON *hobbies = cJSON_CreateArray();
// 添加嵌套对象
cJSON_AddStringToObject(address, "city", "北京");
cJSON_AddStringToObject(address, "district", "海淀区");
cJSON_AddItemToObject(root, "address", address);
// 添加数组(爱好)
cJSON_AddItemToArray(hobbies, cJSON_CreateString("编程"));
cJSON_AddItemToArray(hobbies, cJSON_CreateString("阅读"));
cJSON_AddItemToArray(hobbies, cJSON_CreateString("旅行"));
cJSON_AddItemToObject(root, "hobbies", hobbies);
// 序列化为字符串(无缩进,紧凑格式)
char *json_string = cJSON_PrintUnformatted(root);
if (json_string) {
printf("紧凑JSON字符串:\n%s\n", json_string);
}
free(json_string);
cJSON_Delete(root);
return 0;
}
输出结果:
{"address":{"city":"北京","district":"海淀区"},"hobbies":["编程","阅读","旅行"]}
处理内存泄漏注意事项
cJSON分配的内存需要手动释放,否则会导致内存泄漏,释放规则:
- 调用
cJSON_Print或cJSON_PrintUnformatted生成的字符串需要用free释放。 - 调用
cJSON_CreateXXX创建的JSON节点(及其所有子节点)需要用cJSON_Delete释放。
以下代码会导致内存泄漏:
cJSON *root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "key", "value"); char *json = cJSON_Print(root); // 忘记调用 free(json) 和 cJSON_Delete(root)
正确做法:
char *json = cJSON_Print(root); if (json) free(json); // 先释放字符串 cJSON_Delete(root); // 再释放JSON结构体
其他JSON库简介
除了cJSON,还有两个常用的JSON库:Jansson和Parson,它们各有特点。
Jansson
Jansson是一个功能更丰富的C语言JSON库,支持严格的JSON规范,API设计更现代化(例如使用json_t和json_error_t处理错误),但需要额外依赖(链接-ljansson)。
示例代码(生成JSON):
#include <stdio.h>
#include <jansson.h>
int main() {
json_t *root = json_object();
json_object_set_new(root, "name", json_string("李四"));
json_object_set_new(root, "age", json_integer(30));
char *json_str = json_dumps(root, JSON_INDENT(4)); // 格式化输出
printf("%s\n", json_str);
json_decref(root); // 释放引用(Jansson使用引用计数)
free(json_str);
return 0;
}
Parson
Parson是另一个轻量级JSON库,API风格与cJSON类似,但支持直接从字符串解析和生成JSON(无需手动构建链表),适合简单场景。
示例代码:
#include <stdio.h>
#include "parson.h"
int main() {
JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_value_get_object(root_value);
json_object_set_string(root_object, "name", "王五");
json_object_set_number(root_object, "score", 95.5);
char *json_str = json_serialize_to_string_pretty(root_value);
printf("%s\n", json_str);
json_value_free(root_value); // 释放JSON值
free(json_str);
return 0;
}
总结与选择建议
| 库名 | 特点 | 适用场景 |
|---|---|---|
| cJSON | 单文件实现,轻量级,API简单 | 嵌入式系统、资源受限环境 |
| Jansson | 功能完善,错误处理强,引用计数管理 | 复杂JSON处理、需要严格规范的项目 |
| Parson | API直观,支持直接序列化/反序列化 | 快速开发、中小型项目 |
对于大多数C语言开发者,cJSON是首选:它



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