JsonCpp处理uint64范围边界存异常,能否配置验证?
问题
在使用JsonCpp时发现数值触及uint64范围边界时存在异常行为:
- [0, 2⁶⁴-1]范围内的数值可正常工作;
- 超出范围但处于[2⁶⁴, 2⁶⁴+2¹¹]区间的数值返回0;
- 超过2⁶⁴+2¹¹的数值则抛出异常。
请问此现象是否符合预期?能否配置JsonCpp进行这类验证?
复现代码
#include <iostream> #include <jsoncpp/json/json.h> #include <jsoncpp/json/reader.h> #include <jsoncpp/json/value.h> int main() { // std::string uint64Str = "1234"; // 任何[0, 2**64-1]范围内的数值都能正常工作(输出uint64Str) // std::string uint64Str = "18446744073709551615"; // [0, 2**64-1]范围内的数值都正常,包括2**64-1(输出uint64Str) // std::string uint64Str = "18446744073709551616"; // uint64最大值+1,输出0 // std::string uint64Str = "18446744073709551617"; // uint64最大值+2,输出0 // ... // std::string uint64Str = "18446744073709553663"; // uint64最大值+2048,输出0 // std::string uint64Str = "18446744073709553664"; // uint64最大值+2049,输出0 std::string uint64Str = "18446744073709553665"; // uint64最大值+2050及以上,抛出Json::LogicError异常,信息为"double out of UInt64 range" Json::Value root; Json::Reader reader; bool parsingResult = reader.parse("{\"key\":"+uint64Str+"}", root); std::cout<<root["key"].asUInt64()<<std::endl; return 0; }
回答
现象是否符合预期?
这个现象是JsonCpp内部实现逻辑导致的,但并非设计上的预期行为,本质是浮点数精度丢失引发的边界问题:
- JsonCpp默认将JSON数值解析为
double类型,而double仅能精确表示2⁵³以内的整数。对于超过2⁵³的整数,double无法精准存储,会出现舍入。 - 当数值处于[2⁶⁴, 2⁶⁴+2¹¹]区间时,
double存储后转换回uint64会触发溢出,最终返回0;当数值超过2⁶⁴+2¹¹时,double的表示会超出uint64的可转换范围,触发显式的范围检查,抛出异常。
能否配置JsonCpp进行这类验证?
可以通过配置解析器开启严格的数值范围验证,避免模糊行为:
- 弃用已过时的
Json::Reader,改用Json::CharReaderBuilder,并开启严格模式:Json::CharReaderBuilder builder; builder["collectComments"] = false; // 开启严格数值范围检查 builder["strictMode"] = true; std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); std::string errors; std::string jsonStr = "{\"key\":" + uint64Str + "}"; bool parsingResult = reader->parse(jsonStr.c_str(), jsonStr.c_str() + jsonStr.size(), &root, &errors); - 开启
strictMode后,任何超出uint64范围的数值在解析阶段就会直接抛出异常,不会出现返回0的情况。 - 另外,部分新版本的JsonCpp支持将数值直接解析为
uint64_t类型(而非默认double),需确保JSON数值类型明确,并配置对应解析选项。
内容的提问来源于stack exchange,提问作者Danny Cohen
相关产品推荐
相关产品推荐

