nlohmann/json 3.11 原生稳定支持 cbor,提供开箱即用的 from_cbor/to_cbor 静态接口;解析需传入完整合法 cbor 字节流,长度必须精确,否则抛出 parse_error::parse_error_112 异常。

nlohmann/json 3.11 是当前最直接、最稳妥的方案,无需额外依赖或手写解析器。 它把 CBOR 当作一等公民支持,to_cbor 和 from_cbor 是开箱即用的静态接口,不是实验性功能,也不是插件——从 3.11 版本起已稳定集成进主头文件。
用 nlohmann::json::from_cbor 解析二进制数据
这是最常用路径:把原始 std::vector<uint8_t></uint8_t> 或 const uint8_t* + 长度喂给 from_cbor,它会返回一个标准 json 对象,后续操作和处理普通 JSON 完全一致。
- 输入必须是完整、合法的 CBOR 字节流;截断或损坏会导致
parse_error异常,错误码通常是parse_error::parse_error_112 - 不接受带前导/尾随垃圾字节的数据,哪怕只多一个
0x00也会失败 - 如果数据来自网络 socket 或文件读取,务必确认
size精确匹配实际有效字节数,别用strlen或其他文本函数判断 - 示例:
std::vector<uint8_t> raw_data = {/* ... 来自某处的CBOR字节 ... */}; try { nlohmann::json j = nlohmann::json::from_cbor(raw_data); std::cout () </uint8_t>
处理 CBOR 特有类型(如标签、二进制字符串)
CBOR 支持 JSON 原生没有的类型,比如 byte string(对应 bytes)、时间戳(tag 1)、URI(tag 32)等。nlohmann/json 默认将 byte string 映射为 std::vector<uint8_t></uint8_t>,但不会自动识别 tag 含义。
-
std::vector<uint8_t></uint8_t>类型字段可用j["payload"].get<:vector>>()</:vector>安全提取 - 遇到带 tag 的数据(如 CBOR tag 1 时间戳),
from_cbor默认保留为json::value_t::binary或退化为数组,不会自动转成std::chrono::system_clock::time_point - 若需语义还原,得手动检查
j.is_binary()或用j.type_name()判断,再按 tag 编号做二次解析 - 不推荐依赖自动 tag 解析——nlohmann/json 暂未内置 tag 语义处理器,强行开启可能引入未定义行为
性能与内存注意事项
CBOR 解析比 JSON 快,但快得有限度;真正瓶颈常在后续 C++ 对象映射,而非解析本身。
-
from_cbor是值语义操作,会拷贝全部数据;对 >1MB 的 CBOR blob,考虑用json::from_cbor_ref(若存在)或改用 SAX 接口(需自行实现 handler) - 频繁解析小对象时,注意
json构造/析构开销;可复用局部json变量,避免反复分配内部basic_json结构 - 编译时确保启用
-O2或更高优化级,CBOR 解码路径含大量分支预测,未优化下性能优势会被抹平 - 调试构建(
DEBUG宏启用)下异常检查开销显著,生产环境务必关闭
替代方案为什么通常不值得选
单独引入 libcbor 或 QCBOR 看似“更底层”,但实际增加维护负担,且无法复用你已有的 JSON 处理逻辑。
-
libcborC API 需手动管理cbor_item_t*生命周期,容易内存泄漏或 use-after-free -
QCBOR不支持 C++ RAII,解析后仍需手动遍历树并映射到 C++ 类型,代码量翻倍 - reflect-cpp 虽支持 CBOR,但它面向结构体反射,不适合动态 schema 或未知结构的 CBOR 数据
- 除非你在裸机/资源极度受限环境(如无 STL 的 freestanding C++),否则没必要绕过 nlohmann/json
真正容易被忽略的是 CBOR 的“静默兼容性”:它能表示 JSON 不能表达的值(如 NaN、-0、二进制块),但一旦传给只认 JSON 的下游系统,这些信息就丢了——解析后立刻校验关键字段类型,比事后 debug 更省时间。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











