json-c浮点数序列化异常:不同服务器返回带.0的指数格式
解决json-c在openSUSE Leap上的浮点数序列化格式错误问题
问题根源
你遇到的-5.3022e+05.0这种非法JSON格式,是因为CentOS 8.5和openSUSE Leap使用的glibc版本对printf格式化字符串%.5g的实现不一致。openSUSE上的glibc在处理大数值浮点数时,错误地在科学计数法的指数部分后追加了.0,导致JSON解析失败。你已经确认直接调用C库就会触发问题,说明和JNI、Tomcat等上层环节无关,就是底层的格式化逻辑问题。
解决方案
1. 更换浮点数格式化字符串
直接替换你当前的序列化配置,用更稳定的格式避免glibc的这个异常行为:
// 推荐:用%g自动适配格式,多数场景下不会生成带多余.0的科学计数格式 json_c_set_serialization_double_format("%g", JSON_C_OPTION_GLOBAL); // 备选1:固定小数格式(适合数值范围不大的场景,输出如-530220.00000) // json_c_set_serialization_double_format("%.5f", JSON_C_OPTION_GLOBAL); // 备选2:强制科学计数法(格式一致,输出如-5.30220e+05) // json_c_set_serialization_double_format("%.5e", JSON_C_OPTION_GLOBAL);
优先测试%g,它会自动在普通十进制和科学计数法之间切换,且几乎所有glibc版本都能正确处理,不会生成非法格式。
2. 检查并升级json-c版本
先确认两个系统上的json-c版本差异:
# CentOS上查看版本 rpm -q json-c # openSUSE上查看版本 zypper info json-c
如果openSUSE的json-c版本比CentOS旧,建议升级到和CentOS一致的版本或者最新稳定版——旧版json-c的浮点数序列化逻辑可能存在bug,升级后大概率能解决问题。
3. 手动区分整数/浮点数存入JSON
如果上面的方法都无效,可以在C代码里手动判断浮点数是否为整数,分别用整数或浮点数类型存入JSON对象,从根源避免科学计数法的格式问题:
#include <math.h> #include <json-c/json.h> json_object* create_json_num(double val) { // 用极小阈值判断浮点数是否为整数(避免精度误差) if (fabs(val - round(val)) < 1e-9) { return json_object_new_int64((int64_t)round(val)); } else { return json_object_new_double(val); } }
这样像-530220.0这类整数型浮点数会以-530220的整数格式输出,不会触发科学计数法的异常格式化。
验证方法
在openSUSE上编译一段测试代码,快速验证修复效果:
#include <stdio.h> #include <json-c/json.h> int main() { // 用你选择的格式化字符串 json_c_set_serialization_double_format("%g", JSON_C_OPTION_GLOBAL); json_object* arr = json_object_new_array(); json_object_array_add(arr, json_object_new_double(-530220.0)); json_object_array_add(arr, json_object_new_double(123.456)); const char* json_str = json_object_to_json_string(arr); printf("生成的JSON:%s\n", json_str); json_object_put(arr); return 0; }
编译运行:
gcc test_json.c -o test_json -ljson-c ./test_json
确认输出的JSON数值格式合法,没有多余的.0后缀即可。
内容的提问来源于stack exchange,提问作者dargaud
相关产品推荐
相关产品推荐

