std::stoi/stoll会截断大整数因溢出返回极值或异常;nlohmann/json默认解析为int64_t/double导致精度丢失;推荐用boost/json获取原始数字字符串再交由boost/multiprecision精确构造。

为什么 std::stoi 和 std::stoll 会截断大整数
JSON 中的数字如 9223372036854775808(即 2⁶³)已超出 long long 的最大值(9223372036854775807),调用 std::stoll 会触发溢出,返回 LLONG_MAX 或抛异常(取决于实现和标志位),精度直接丢失。更麻烦的是,很多 JSON 库(如 nlohmann/json)默认将大整数解析为 int64_t 或 double,后者连 2^53 以上整数都无法精确表示。
用 nlohmann/json 保留原始字符串再手动解析高精度整数
核心思路:绕过库的自动数字转换,把数字字段当字符串读出来,再交给任意精度整数库处理。nlohmann 支持通过 get_ref<const json::string_t>()</const> 强制取原始字符串值,前提是 JSON 文本中该数字**未被引号包围**但解析时未被转成 number 类型——这不可控;更可靠的方式是预处理或启用「禁止自动类型转换」模式。
- 启用
json::parse(..., /* allow_exceptions */ true, /* ignore_comments */ false, /* parse_number */ false)不现实(nlohmann 不支持关闭数字解析) - 实际可行做法:用
json::is_number_integer()判断后,改用dump()提取原始 token 字符串,再正则或手动切掉空格和逗号边界 —— 但易受格式影响 - 推荐方案:改用支持「无损数字解析」的库,如
boost/json(v1.75+)或simdjson(可访问原始 UTF-8 数字字节)
用 boost/json 直接获取未解析的数字字节
boost/json 提供 value::if_int64() / if_uint64() 等安全检查,但它仍受限于整型范围;真正关键的是它的 value::kind() == kind::number 且支持 value::to_string() 返回原始数字文本(不含科学计数法、无舍入)。配合 boost/multiprecision/cpp_int.hpp 即可无损构造:
#include <boost/json.hpp>
#include <boost/multiprecision/cpp_int.hpp>
namespace json = boost::json;
namespace mp = boost::multiprecision;
<p>json::value jv = json::parse(R"({"id": 123456789012345678901234567890})");
if (jv.is_number())
{
std::string num_str = jv.to_string(); // → "123456789012345678901234567890"
mp::cpp_int big_id(num_str); // 精确构造,无精度损失
}</p>自己解析字符串时要注意的边界细节
即使拿到原始字符串,直接丢给 cpp_int 构造函数也不够稳妥——JSON 允许前导空格、负号、但不允许前导零(除单独的 "0")。RFC 8259 明确规定:0123 是非法数字,但某些宽松解析器可能放过。实际工程中需校验:
立即学习“C++免费学习笔记(深入)”;
- 跳过开头空格(
std::isspace),检查是否以'-'开头 - 若长度 > 1,首字符为
'0'后紧跟数字 → 非法,应报错或按业务规则处理 - 确保所有剩余字符都是 ASCII 数字
'0'–'9',不能含小数点或e/E -
cpp_int构造接受带符号字符串,但若输入超长(如百万位),构造本身可能慢,需考虑流式解析或分段校验
大整数不是“解析完就完事”,从 JSON 拆出字符串那一刻起,校验、范围预期、序列化回传时的格式一致性,都得闭环考虑。


















