引言
在现代软件开发中,数据交换无处不在------前端和后端通信、服务之间调用、配置文件读写、日志记录......这些场景都需要一种轻量、通用、易读的数据格式。
JSON (JavaScript Object Notation)就是目前最流行的选择。它诞生于 2001 年,原本是 JavaScript 的一个子集,但因为足够简单,很快被所有主流语言支持,成为事实上的数据交换标准。
本文不深挖理论,聚焦于项目实战:JSON 长什么样、怎么写、在 C/C++ 项目中怎么用。

第一部分:JSON 是什么
一、一句话定义
JSON 是一种用文本表示结构化数据的格式。它只有两种结构:
-
对象 :
{ "key": value, ... }--- 键值对集合 -
数组 :
[ value, value, ... ]--- 有序值列表
二、一个完整的例子
{
"name": "张三",
"age": 25,
"isStudent": false,
"hobbies": ["读书", "编程", "跑步"],
"address": {
"city": "北京",
"district": "海淀区"
},
"phone": null
}
就这么简单。上面这段 JSON 描述了一个人的信息,任何语言的程序员都能看懂。
第二部分:JSON 的六种数据类型

完整示例:各种类型混合
{
"string": "文本",
"number": 42,
"float": 3.14,
"bool": true,
"null_value": null,
"array": [1, "two", false, null],
"object": {
"nested": {
"deep": "可以一直嵌套"
}
}
}
第三部分:JSON 的语法规则
一、必须遵守的规则
| 规则 | 正确 | 错误 |
|---|---|---|
| 键必须用双引号 | {"name": "张三"} |
{name: "张三"} |
| 字符串必须用双引号 | "hello" |
'hello' |
| 不能有尾随逗号 | [1, 2, 3] |
[1, 2, 3,] |
| 不能有注释 | {"a": 1} |
{"a": 1 // 注释} |
| 数字不能有前导零 | 42 |
042 |
二、常见错误示例
// ❌ 错误1:键没有引号
{name: "张三"}
// ❌ 错误2:用了单引号
{'name': '张三'}
// ❌ 错误3:尾随逗号
{"a": 1, "b": 2,}
// ❌ 错误4:注释
{
"a": 1 // 这是注释
}
// ❌ 错误5:NaN、Infinity(JSON 不支持)
{"value": NaN}
// ✅ 正确写法
{"name": "张三", "age": 25}
第四部分:为什么项目中用 JSON
一、JSON vs 其他格式
| 格式 | 可读性 | 体积 | 解析速度 | 语言支持 |
|---|---|---|---|---|
| JSON | ✅ 好 | 中 | 快 | 所有语言 |
| XML | ✅ 好 | 大 | 慢 | 所有语言 |
| YAML | ✅ 最好 | 小 | 慢 | 部分语言 |
| Protobuf | ❌ 二进制 | 最小 | 最快 | 需编译 |
| 自定义文本 | 视情况 | 小 | 快 | 需自己实现 |
二、JSON 的三大优势

三、项目中的典型场景
| 场景 | 示例 |
|---|---|
| 前后端通信 | 浏览器发 {"username":"admin","password":"123"} 给服务器 |
| 配置文件 | 程序的 config.json 存数据库地址、端口等 |
| API 响应 | 服务器返回 {"code":0,"data":[...],"msg":"成功"} |
| 日志记录 | 每条日志是一个 JSON 对象 |
| 消息队列 | 生产者发送 JSON,消费者解析 |
| 数据库存储 | MongoDB 直接存 JSON,Redis 存 JSON 字符串 |
第五部分:C/C++ 项目中使用 JSON
一、常用 JSON 库
| 库 | 语言 | 特点 | 推荐度 |
|---|---|---|---|
| cJSON | C | 轻量、单文件、无依赖 | ⭐⭐⭐⭐⭐ |
| nlohmann/json | C++ | 现代 C++ 接口、简洁 | ⭐⭐⭐⭐⭐ |
| RapidJSON | C++ | 腾讯开源、性能极高 | ⭐⭐⭐⭐ |
| jsoncpp | C++ | 老牌库 | ⭐⭐⭐ |
二、cJSON 使用示例(C 语言)
安装:cJSON 只有两个文件,直接拖进项目即可。
bash
# 下载
git clone https://github.com/DaveGamble/cJSON.git
# 复制 cJSON.c 和 cJSON.h 到项目
生成 JSON:
cpp
#include <stdio.h>
#include "cJSON.h"
int main() {
// 创建根对象
cJSON* root = cJSON_CreateObject();
// 添加字段
cJSON_AddStringToObject(root, "name", "张三");
cJSON_AddNumberToObject(root, "age", 25);
cJSON_AddBoolToObject(root, "isStudent", 0);
// 创建数组
cJSON* hobbies = cJSON_CreateArray();
cJSON_AddItemToArray(hobbies, cJSON_CreateString("读书"));
cJSON_AddItemToArray(hobbies, cJSON_CreateString("编程"));
cJSON_AddItemToObject(root, "hobbies", hobbies);
// 创建嵌套对象
cJSON* address = cJSON_CreateObject();
cJSON_AddStringToObject(address, "city", "北京");
cJSON_AddItemToObject(root, "address", address);
// 输出为字符串
char* jsonStr = cJSON_Print(root);
printf("%s\n", jsonStr);
// 释放内存
free(jsonStr);
cJSON_Delete(root);
return 0;
}
输出:
cpp
{
"name": "张三",
"age": 25,
"isStudent": false,
"hobbies": ["读书", "编程"],
"address": {
"city": "北京"
}
}
解析 JSON:
cpp
#include <stdio.h>
#include "cJSON.h"
int main() {
const char* jsonStr = "{\"name\":\"张三\",\"age\":25,\"hobbies\":[\"读书\",\"编程\"]}";
// 解析
cJSON* root = cJSON_Parse(jsonStr);
if (root == NULL) {
printf("解析失败\n");
return -1;
}
// 读取字符串
cJSON* name = cJSON_GetObjectItem(root, "name");
if (name && cJSON_IsString(name)) {
printf("name: %s\n", name->valuestring);
}
// 读取数字
cJSON* age = cJSON_GetObjectItem(root, "age");
if (age && cJSON_IsNumber(age)) {
printf("age: %d\n", age->valueint);
}
// 读取数组
cJSON* hobbies = cJSON_GetObjectItem(root, "hobbies");
if (hobbies && cJSON_IsArray(hobbies)) {
int size = cJSON_GetArraySize(hobbies);
printf("hobbies (%d):\n", size);
for (int i = 0; i < size; i++) {
cJSON* item = cJSON_GetArrayItem(hobbies, i);
printf(" %s\n", item->valuestring);
}
}
// 释放
cJSON_Delete(root);
return 0;
}
输出:
name: 张三
age: 25
hobbies (2):
读书
编程
三、nlohmann/json 使用示例(C++)
安装:只需一个头文件。
bash
# 下载 json.hpp
wget https://github.com/nlohmann/json/releases/download/v3.11.3/json.hpp
cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main() {
// ===== 构建 JSON =====
json j;
j["name"] = "张三";
j["age"] = 25;
j["hobbies"] = {"读书", "编程", "跑步"};
j["address"]["city"] = "北京";
j["address"]["district"] = "海淀区";
// 输出为格式化字符串
std::cout << j.dump(4) << std::endl;
// ===== 解析 JSON =====
std::string jsonStr = R"({
"name": "李四",
"age": 30,
"hobbies": ["游泳", "摄影"]
})";
json parsed = json::parse(jsonStr);
// 读取
std::cout << "name: " << parsed["name"] << std::endl;
std::cout << "age: " << parsed["age"] << std::endl;
for (const auto& h : parsed["hobbies"]) {
std::cout << " hobby: " << h << std::endl;
}
// 判断字段是否存在
if (parsed.contains("phone")) {
std::cout << "有 phone 字段" << std::endl;
} else {
std::cout << "没有 phone 字段" << std::endl;
}
return 0;
}
输出:
cpp
{
"address": {
"city": "北京",
"district": "海淀区"
},
"age": 25,
"hobbies": ["读书", "编程", "跑步"],
"name": "张三"
}
name: 李四
age: 30
hobby: 游泳
hobby: 摄影
没有 phone 字段
第六部分:项目中的 JSON 设计规范
一、API 响应的标准格式
cpp
{
"code": 0,
"message": "success",
"data": {
"id": 1001,
"name": "张三"
}
}
| 字段 | 作用 |
|---|---|
code |
状态码:0 表示成功,非 0 表示错误 |
message |
错误描述(成功时可省略) |
data |
实际数据(可以是对象、数组、null) |
二、分页响应
cpp
{
"code": 0,
"data": {
"list": [
{"id": 1, "name": "张三"},
{"id": 2, "name": "李四"}
],
"total": 100,
"page": 1,
"pageSize": 10
}
}
三、错误响应
cpp
{
"code": 1001,
"message": "用户名或密码错误",
"data": null
}
第七部分:JSON 的常见坑

转义字符速查
| 原字符 | JSON 中的写法 |
|---|---|
" |
\" |
\ |
\\ |
| 换行 | \n |
| 制表符 | \t |
| 回车 | \r |
总结
一、核心要点
| 要点 | 内容 |
|---|---|
| 定义 | 轻量级文本数据格式,用对象和数组表示结构 |
| 六种类型 | 字符串、数字、布尔、null、对象、数组 |
| 语法规则 | 双引号、无尾随逗号、无注释 |
| 项目用途 | 前后端通信、配置、日志、API 响应 |
| C 库 | cJSON(单文件、轻量) |
| C++ 库 | nlohmann/json(现代、简洁) |
二、一句话记忆
JSON 用 {} 表示对象、[] 表示数组,支持字符串、数字、布尔、null 六种类型。语法要求双引号、无注释、无尾随逗号。项目中主要用于前后端通信和配置存储,C 用 cJSON、C++ 用 nlohmann/json。