嵌入式C++不宜直接用JSON库序列化,因JSON文本体积大、解析耗资源,易致MCU内存溢出;CBOR更紧凑高效,推荐tinycbor库——纯C、零malloc、API清晰、易于静态集成。

为什么嵌入式 C++ 不该直接用 JSON 库做序列化
JSON 文本体积大、解析耗 CPU 和内存,对 RAM 通常只有几十 KB 的 MCU 来说,jsoncpp 或 ArduinoJson(尤其在动态分配模式下)容易触发 OOM 或栈溢出。CBOR 是 RFC 7049 定义的二进制格式,天然紧凑、无字符串重复解析、支持整数/浮点/字节串原生编码,更适合资源受限环境。
选哪个 CBOR 库:ciborium vs. tinycbor vs. QCBOR
实测在 ARM Cortex-M3/M4(GCC 10 + -Os)上:
-
ciborium(Rust 写的 C++ 绑定)依赖 STL 和异常,嵌入式基本不可用 -
tinycbor(Intel 开源)纯 C,零 malloc,API 清晰,cbor_encoder_create/cbor_decoder_init可静态分配缓冲区,推荐首选 -
QCBOR(QPX 开发)更轻量(~4KB Flash),但 API 略反直觉(如 map 必须先写 key 再写 value),调试时易错序
结论:tinycbor 平衡性最好,GitHub 搜 intel/tinycbor,取 src/ 下 4 个 .c/.h 文件即可集成。
如何用 tinycbor 编码一个带时间戳和传感器值的结构体
典型场景:把 struct SensorReport { uint32_t ts; int16_t temp; uint8_t batt; }; 编成 CBOR map(而非 array),便于未来字段扩展。
立即学习“C++免费学习笔记(深入)”;
关键点:
- 必须用
cbor_encoder_init初始化 encoder,传入你预分配的uint8_t buf[64]—— 别用栈上太小的数组,map header 至少占 2 字节 - map 长度要预先知道(或用
cbor_encoder_close_container_checked回填),建议固定字段数,用cbor_encode_text_stringz写 key(如"ts"),再用cbor_encode_uint/cbor_encode_int写 value - 别漏掉
cbor_encoder_get_buffer_size—— 它返回实际编码长度,不是 buf 大小
uint8_t buf[64]; CborEncoder encoder; cbor_encoder_init(&encoder, buf, sizeof(buf), 0); CborEncoder map; cbor_encoder_create_map(&encoder, &map, 3); // 明确字段数 cbor_encode_text_stringz(&map, "ts"); cbor_encode_uint(&map, report.ts); cbor_encode_text_stringz(&map, "temp"); cbor_encode_int(&map, report.temp); cbor_encode_text_stringz(&map, "batt"); cbor_encode_uint(&map, report.batt); cbor_encoder_close_container_checked(&encoder, &map); size_t encoded_len = cbor_encoder_get_buffer_size(&encoder, buf);
解码时最容易踩的坑:类型校验和 buffer 边界
CBOR 允许整数以不同长度编码(如 uint8 或 uint32),但你的 struct 字段是固定宽度。不校验类型直接 cbor_value_get_int 可能截断或符号错误。
- 务必用
cbor_value_get_type先判断当前项是CborIntegerType,再用cbor_value_get_raw_integer获取原始值,自己做范围检查 - 解码前确认
cbor_parser_init的flags设为0(禁用 float 转 int 自动转换,避免精度丢失) - buffer 传给
cbor_parser_init时,长度必须是真实数据长度(从encoded_len得来),不能传整个buf大小,否则解析器可能读越界
复杂点在于 map 的 key 必须严格匹配(大小写敏感、无空格),且 CBOR 不保证 key 顺序 —— 所以解码逻辑不能依赖遍历顺序,得用字符串比对跳转。


















