当前位置: 首页 > news >正文

C/C++ json库

文章目录

  • 一、介绍
    • 1.1 json 介绍
  • 二、C/C++ json 库选型
    • 2.1 选型范围
    • 2.2 jsoncpp
      • 2.2.2 jsoncpp 编译和交叉编译
    • 2.3 rapidjson
    • 2.4 nlohmann/json
    • 2.5 sonic-cpp
  • 五、常见问题
    • 5.1 jsoncpp 中关于浮点数的控制和中文显示问题
    • 5.2 jsoncpp序列化double类型时精度损失问题的解决办法

一、介绍

1.1 json 介绍

  • 官网:http://www.json.org/json-zh.html
  • JSON是什么?如何正确理解?

二、C/C++ json 库选型

2.1 选型范围

  • 资料
    • 官网:http://www.json.org/json-zh.html
    • 开源库比较:https://github.com/miloyip/nativejson-benchmark
    • C++中json库的选择
    • C/C++ 开源 JSON 程序库性能及标准符合程度评测
  • 开源库
    • Rapidjson、Rapidjson_FullPrec、Rapidjson_AutoUTF
    • nlohmann / json
    • jsoncpp
  • 结论:
    • 注重最佳性能,选 Rapidjson (cereal序列化库使用)
    • 注重易用性,选 jsoncpp (ros 使用)、nlohmann / json

在这里插入图片描述

2.2 jsoncpp

  • 精度控制:precision
    • 15,16,17:原值会变
    • 0-14:原值不变的情况下,四舍五入

2.2.2 jsoncpp 编译和交叉编译

  • jsoncpp 的编译和交叉编译

  • 编译

    mkdir build; cd build
    cmake -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_SHARED_LIBS=ON \
    -DCMAKE_INSTALL_PREFIX=`pwd`/result \
    -DJSONCPP_WITH_TESTS=OFF \ ..
    make install -j4
    
  • 交叉编译

    mkdir build; cd build
    cmake -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_SHARED_LIBS=ON \
    -DCMAKE_INSTALL_PREFIX=`pwd`/result \
    -DJSONCPP_WITH_TESTS=OFF \ ..
    -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \ ..
    make install -j4# toolchain.cmake 定义交叉编译环境变量
    SET(CMAKE_SYSROOT "/opt/fslc-x11/2.4.4/sysroots/armv7at2hf-neon-fslc-linux-gnueabi")
    set(CMAKE_SYSTEM_NAME Linux)
    set(CMAKE_SYSTEM_PROCESSOR arm)
    set(TOOLS /opt/fslc-x11/2.4.4/sysroots/x86_64-fslcsdk-linux/usr/bin/arm-fslc-linux-gnueabi)
    set(CMAKE_C_COMPILER "${TOOLS}/arm-fslc-linux-gnueabi-gcc")
    set(CMAKE_CXX_COMPILER "${TOOLS}/arm-fslc-linux-gnueabi-g++")
    set(CMAKE_AR "${TOOLS}/arm-fslc-linux-gnueabi-ar")
    
  • include/json

  • lib/cmake/xxx.cmake

  • lib/pkgconfig/jsoncpp.pc

  • pkgconfig

    mayue@PC-MAYUE:/mnt/d/hik/opensource/jsoncpp-1.9.5/build/result/lib$ cat pkgconfig/jsoncpp.pc
    prefix=/mnt/d/hik/opensource/jsoncpp-1.9.5/build/result
    exec_prefix=/mnt/d/hik/opensource/jsoncpp-1.9.5/build/result
    libdir=${exec_prefix}/lib
    includedir=${prefix}/includeName: jsoncpp
    Description: A C++ library for interacting with JSON
    Version: 1.9.5
    URL: https://github.com/open-source-parsers/jsoncpp
    Libs: -L${libdir} -ljsoncpp
    Cflags: -I${includedir}
    

指定连接静态库

g++ jsoncpp-test.cpp -I./include -L ./lib -l:libjsoncpp.a

2.3 rapidjson

  • http://rapidjson.org/

2.4 nlohmann/json

  • https://github.com/nlohmann/json
  • nlohmann入门使用总结

2.5 sonic-cpp

  • 当前仅支持amd64
  • 开源 C++ JSON 库 sonic-cpp解析性能为 rapidjson 的 2.5 倍
  • 性能提升 2.5 倍!字节开源高性能 C++ JSON 库 sonic-cpp

五、常见问题

5.1 jsoncpp 中关于浮点数的控制和中文显示问题

  • jsoncpp 中关于浮点数的控制和中文显示问题

5.2 jsoncpp序列化double类型时精度损失问题的解决办法

  • jsoncpp序列化double类型时精度损失问题的解决办法

解决办法1:此法不需要改源码,使用StreamWriterBuilder进行序列化

#include <json/json.h>
#include <json/writer.h>
#include <iostream>
#include <string>void test_precision(int precision)
{Json::Value root;root["pi"] = 3.1415926;root["count"] = 43.32558674566;Json::StreamWriterBuilder builder;//设置精度 注意这个默认设置的是数字总长度 //如果想设置小数点后的位数需设置precisionType为decimalbuilder.settings_["precision"] = precision;//设置精度类型 只可设置2种字符串 significant精度位数为数字总长度(jsoncpp默认为此类型) decimal精度位数为小数点后的长度builder.settings_["precisionType"] = "decimal";// 设置输出为紧凑格式,不带换行和空格builder["commentStyle"] = "None";   // 防止输出注释,默认就是nonebuilder["indentation"] = "";        // 空字符串表示不缩进std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());std::ostringstream oss;writer->write(root, &oss);std::string jsonText = oss.str();// 输出 JSON 字符串std::cout << "specified precision: " << precision << ", content:" << jsonText << std::endl;
}int main() {for(int i=17; i>=0; i--){test_precision(i);}return 0;
}
specified precision: 17, content:{"count":43.32558674565999723,"pi":3.14159260000000007}
specified precision: 16, content:{"count":43.3255867456599972,"pi":3.1415926000000001}
specified precision: 15, content:{"count":43.325586745659997,"pi":3.1415926}
specified precision: 14, content:{"count":43.32558674566,"pi":3.1415926}
specified precision: 13, content:{"count":43.32558674566,"pi":3.1415926}
specified precision: 12, content:{"count":43.32558674566,"pi":3.1415926}
specified precision: 11, content:{"count":43.32558674566,"pi":3.1415926}
specified precision: 10, content:{"count":43.3255867457,"pi":3.1415926}
specified precision: 9, content:{"count":43.325586746,"pi":3.1415926}
specified precision: 8, content:{"count":43.32558675,"pi":3.1415926}
specified precision: 7, content:{"count":43.3255867,"pi":3.1415926}
specified precision: 6, content:{"count":43.325587,"pi":3.141593}
specified precision: 5, content:{"count":43.32559,"pi":3.14159}
specified precision: 4, content:{"count":43.3256,"pi":3.1416}
specified precision: 3, content:{"count":43.326,"pi":3.142}
specified precision: 2, content:{"count":43.33,"pi":3.14}
specified precision: 1, content:{"count":43.3,"pi":3.1}
specified precision: 0, content:{"count":43,"pi":3}
  • 精度控制:precision

    • 15,16,17:原值会变、四舍五入
    • 0-14:原值不变的情况下,四舍五入
  • 特别注意:精度设置一定要大于你需求的精度位数,比如需要三位可以设置4位或5位,因为最后一位可能会不准(做了四舍五入)

不足之处:
StreamWriterBuilder序列化的字符串是可读形式的,就像上面的输出,是有换行和缩进的(转换效率会比FastWrite低),我的服务端代码里其实不需要转换json为可读的,更需要的是效率,所以还有下面一种方法改FasetWrite源码

解决办法2:此法需要改源码,使用FastWriter进行序列化

  • 注意:需升级jsoncpp到最新版本1.9.5版本

  • 修改源码(writer.h):FastWriter类新增2个成员变量(precision_和precisionType_)和成员函数(set_precision和set_precisionType)

    #if defined(_MSC_VER)
    #pragma warning(push)
    #pragma warning(disable : 4996) // Deriving from deprecated class
    #endif
    class JSON_API FastWriter: public Writer {
    public:FastWriter();~FastWriter() override = default;void enableYAMLCompatibility();/** \brief Drop the "null" string from the writer's output for nullValues.* Strictly speaking, this is not valid JSON. But when the output is being* fed to a browser's JavaScript, it makes for smaller output and the* browser can handle the output just fine.*/void dropNullPlaceholders();void omitEndingLineFeed();public: // overridden from WriterString write(const Value& root) override;//设置精度位数void set_precision(unsigned int precision) { precision_ = (precision > 17)?17:precision; };//设置精度类型 默认为数字总长//入参:isDecimal true表示类型为小数点后长度 false表示类型为数字总长void set_precisionType(bool isDecimal) { isDecimal ? (precisionType_ = PrecisionType::decimalPlaces) : (precisionType_ = PrecisionType::significantDigits); };private:void writeValue(const Value& value);String document_;bool yamlCompatibilityEnabled_{false};bool dropNullPlaceholders_{false};bool omitEndingLineFeed_{false};int precision_{ 17 };//精度位数 默认17位PrecisionType precisionType_{ PrecisionType::significantDigits };//精度类型 默认为数字总长
    };
    #if defined(_MSC_VER)
    #pragma warning(pop)
    #endif
    
  • 修改源码(json_writer.cpp):只修改了1行代码,FastWriter::writeValue函数中case realValue的处理中调用的valueToString新增了2个参数传递(源码中没有传递用的函数默认值,现在传了并且可以通过新增的2个成员函数进行设置)

    void FastWriter::writeValue(const Value& value) {switch (value.type()) {case nullValue:if (!dropNullPlaceholders_)document_ += "null";break;case intValue:document_ += valueToString(value.asLargestInt());break;case uintValue:document_ += valueToString(value.asLargestUInt());break;case realValue://这里原先是document_ += valueToString(value.asDouble());//因为后2个参数没传,所以用的函数默认值即精度位数=17,精度类型=PrecisionType::significantDigits//修改后 现在会传这2个参数,具体值可以通过新增加的2个成员函数设置document_ += valueToString(value.asDouble(), precision_, precisionType_);break;case stringValue: {// Is NULL possible for value.string_? No.char const* str;char const* end;bool ok = value.getString(&str, &end);if (ok)document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));break;}case booleanValue:document_ += valueToString(value.asBool());break;case arrayValue: {document_ += '[';ArrayIndex size = value.size();for (ArrayIndex index = 0; index < size; ++index) {if (index > 0)document_ += ',';writeValue(value[index]);}document_ += ']';} break;case objectValue: {Value::Members members(value.getMemberNames());document_ += '{';for (auto it = members.begin(); it != members.end(); ++it) {const String& name = *it;if (it != members.begin())document_ += ',';document_ += valueToQuotedStringN(name.data(), name.length());document_ += yamlCompatibilityEnabled_ ? ": " : ":";writeValue(value[name]);}document_ += '}';} break;}
    }
    
  • 需要重新编译库,然后demo验证,使用的代码:

    #include <json/json.h>
    #include <json/writer.h>
    #include <iostream>
    #include <string>void test_precision(int precision)
    {Json::Value obj;Json::FastWriter write;write.set_precision(precision);write.set_precisionType(true);obj["d"] = 2.1;obj["d2"] = 9.111;obj["d3"] = 9.123456789;auto rtn = write.write(obj);std::cout << "specified precision: " << precision << ", rtn:" << rtn << std::endl;
    }int main() {for(int i=17; i>=0; i--){test_precision(i);}return 0;
    }
    
    specified precision: 17, rtn:{"d":2.10000000000000009,"d2":9.11100000000000065,"d3":9.12345678900000046}specified precision: 16, rtn:{"d":2.1000000000000001,"d2":9.1110000000000007,"d3":9.1234567890000005}specified precision: 15, rtn:{"d":2.1,"d2":9.111000000000001,"d3":9.123456789}specified precision: 14, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}specified precision: 13, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}specified precision: 12, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}specified precision: 11, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}specified precision: 10, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}specified precision: 9, rtn:{"d":2.1,"d2":9.111,"d3":9.123456789}specified precision: 8, rtn:{"d":2.1,"d2":9.111,"d3":9.12345679}specified precision: 7, rtn:{"d":2.1,"d2":9.111,"d3":9.1234568}specified precision: 6, rtn:{"d":2.1,"d2":9.111,"d3":9.123457}specified precision: 5, rtn:{"d":2.1,"d2":9.111,"d3":9.12346}specified precision: 4, rtn:{"d":2.1,"d2":9.111,"d3":9.1235}specified precision: 3, rtn:{"d":2.1,"d2":9.111,"d3":9.123}specified precision: 2, rtn:{"d":2.1,"d2":9.11,"d3":9.12}specified precision: 1, rtn:{"d":2.1,"d2":9.1,"d3":9.1}specified precision: 0, rtn:{"d":2,"d2":9,"d3":9}

C++ json序列化库有哪些,哪个性能最好

C++中有多种JSON序列化库可供选择,包括但不限于以下几种:

  1. Rapidjson:这是一个非常流行的C++ JSON库,以其高性能著称,由腾讯团队开发 。

  2. nlohmann/json:这是一个现代的、基于C++11的JSON库,以其易用性和直观的接口而受到许多C++程序员的青睐 。

  3. sonic-cpp:由字节跳动STE团队和服务框架团队共同研发的高效JSON库,它利用CPU硬件特性和向量化编程,大幅提高了序列化和反序列化的性能。据报道,其解析性能是rapidjson的2.5倍 。

  4. JsonCpp:这是一个成熟的库,提供了丰富的功能来处理JSON数据。

  5. simdjson:这是一个使用SIMD指令集来加速解析的库,它提供了快速的解析性能,但不支持修改解析后的JSON结构 。

  6. yyjson:这是一个追求解析性能的库,使用链表结构,但在查找数据时性能较差 。

在这些库中,sonic-cpp 被报道为性能最好的库,它不仅提供了高效的解析性能,还解决了其他一些库的缺点,如simdjson和yyjson的问题,并支持高效的增删改查操作 。此外,sonic-cpp已经在字节跳动的多个核心业务中大规模使用,并通过了工程化的考验 。

如果您对性能有极高的要求,sonic-cpp可能是一个不错的选择。然而,选择哪个库还应考虑其他因素,如易用性、社区支持、库的活跃度和维护情况。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 如何在电脑上演示手机上APP,远程排查移动端app问题
  • C#数字医学影像系统(RIS/PACS)源码,Oracle数据库,C/S架构,运行稳定
  • 入坑树莓派(2)——树莓派4B与手机蓝牙通信
  • vue使用了代理跨域,部署上线,使用Nginx配置出现问题,访问不到后端接口
  • 农业旅游与乡村旅游:融合绿色田野与诗意远方的经济新篇章
  • Zookeeper是什么,为什么要用,怎么用?
  • 探索数据的内在结构:使用Scikit-Learn确定聚类数
  • SpringBoot 项目 pom.xml 中 设置 Docker Maven 插件
  • 解决:Linux上SVN 1.12版本以上无法直接存储明文密码
  • 基于ffmepg的视频剪辑
  • Python Linux环境(Centos8)安装minicoda3+jupyterlab
  • vue 字符串格式“[a,b]“转数组
  • Cookies和session区别
  • pdf转换器哪个好?PDF转word工具分享
  • UniApp__微信小程序项目实战 实现长列表分页,通过 onReachBottom 方法上划分次加载数据
  • ➹使用webpack配置多页面应用(MPA)
  • Angular2开发踩坑系列-生产环境编译
  • Docker: 容器互访的三种方式
  • leetcode388. Longest Absolute File Path
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • mysql 5.6 原生Online DDL解析
  • nodejs实现webservice问题总结
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • tweak 支持第三方库
  • Vue ES6 Jade Scss Webpack Gulp
  • Vue.js-Day01
  • vue学习系列(二)vue-cli
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 成为一名优秀的Developer的书单
  • 高程读书笔记 第六章 面向对象程序设计
  • 给Prometheus造假数据的方法
  • 简单基于spring的redis配置(单机和集群模式)
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • ​必胜客礼品卡回收多少钱,回收平台哪家好
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • ​如何在iOS手机上查看应用日志
  • ​学习一下,什么是预包装食品?​
  • #etcd#安装时出错
  • #if和#ifdef区别
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #QT(串口助手-界面)
  • #数学建模# 线性规划问题的Matlab求解
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (003)SlickEdit Unity的补全
  • (03)光刻——半导体电路的绘制
  • (12)Hive调优——count distinct去重优化
  • (2024)docker-compose实战 (8)部署LAMP项目(最终版)
  • (第三期)书生大模型实战营——InternVL(冷笑话大师)部署微调实践
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (每日一问)基础知识:堆与栈的区别
  • (三)mysql_MYSQL(三)
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)