json中大整数丢失精度是因为其数字统一按ieee 754双精度浮点表示,超过2^53-1后无法精确表达;主流库如nlohmann/json、jsoncpp默认使用double解析,需显式转字符串或整型并校验范围。

为什么 JSON 中的大整数会丢失精度
JSON 标准本身不区分 int 和 double,所有数字都按 IEEE 754 双精度浮点表示。当整数超过 2^53 - 1(约 9e15)时,double 无法精确表示每个整数,比如 9007199254740993 解析后可能变成 9007199254740992。nlohmann/json、jsoncpp 等主流库默认都走 double 路径,这是精度丢失的根源。
nlohmann/json:用 get<int64_t>()</int64_t> 或启用 JSON_USE_INT64
它不自动推导大整数为整型,必须显式指定目标类型:
-
j["id"].get<int64_t>()</int64_t>—— 仅适用于 ≤INT64_MAX(约 9.2e18)的整数;若 JSON 中值超出范围,会抛nlohmann::json::out_of_range - 编译前定义
#define JSON_USE_INT64,可让as_integer()、get<int>()</int>等更倾向整型解析,但不改变底层存储——仍需手动取值 - 对超 64 位整数(如微博 UID、区块链 nonce),必须用字符串接收:
j["big_id"].get<:string>()</:string>,再交由boost::multiprecision或自定义解析
jsoncpp:别信 asInt(),优先用 asUInt64() 或字符串
Json::Value::asInt() 返回 int(通常 32 位),asInt64() 才是真正跨平台的 64 位有符号整型。但注意:
-
root["id"].isInt64()必须先调用,否则asInt64()行为未定义 - jsoncpp 不提供无符号 64 位原生支持,
asUInt64()是非标准扩展,部分旧版本不带;稳妥做法仍是asString()+ 手动std::stoull() - 若 JSON 字段实际是字符串形式的大数(如
"12345678901234567890"),直接asInt64()会失败,必须先判断isString()
真正安全的通用策略:一律按字符串读,业务层再转换
只要你的协议里明确某个字段是“大整数 ID”,就不要依赖库的数字解析能力。这是最可控的做法:
- 用
j["order_id"].get<:string>()</:string>(nlohmann)或root["order_id"].asString()(jsoncpp)拿到原始字符串 - 校验字符串是否全数字(排除负号、小数点等),再决定用
std::stoll()、std::stoull()或高精度库处理 - 避免在日志、调试输出中直接打印
j["id"]——它可能已失真;打印前务必.dump()或转字符串
大数值精度问题本质不是库缺陷,而是 JSON 规范与 C++ 类型系统的天然错配。绕过数字解析、守住字符串源头,是目前最可靠、兼容性最好的实践。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











