尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

DB Browser for SQLite 内置的 nlohmann/json:单头文件现代 C++ JSON 库完整实战指南

DB Browser for SQLite 内置的 nlohmann/json:单头文件现代 C++ JSON 库完整实战指南 数据库数据库客户端桌面应用【免费下载链接】sqlitebrowserOfficial home of the DB Browser for SQLite (DB4S) project. Previously known as SQLite Database Browser and Database Browser for SQLite. Website at:项目地址https://gitcode.com/gh_mirrors/sq/sqlitebrowser点击查看免费下载导读本指南以 DB Browser for SQLiteDB4S仓库内随附的 nlohmann/json 官方文档JSON for Modern C为核心全面讲解这一以现代 C 一等数据类型体验著称的单头文件 JSON 库从设计目标、构造与序列化/反序列化、STL 式容器访问到 JSON Pointer/Patch、任意自定义类型转换、枚举映射以及 BSON/CBOR/MessagePack/UBJSON 二进制格式。文末结合 DB4S 源码展示它在查询结果 JSON 导出、单元格 JSON 数据校验与格式化中的真实落地用法帮助你既能直接上手该库也能读懂 DB4S 内部的数据交换实现。关联文档libs/json/README.md仓库内置头文件libs/json/json.hpp版本 3.10.4单头文件约 2.6 万行。设计目标为什么选它nlohmann/json 的设计目标决定了它非常适合被嵌入到像 DB4S 这样的 C 桌面应用中直观的语法。借助现代 C 的运算符重载JSON 在代码中拥有接近 Python 般的一等数据类型体验——直接j[key] value即可构造嵌套结构无需手写 DOM 构建器。极简集成。整个库只有一个头文件json.hpp即仓库中的 libs/json/json.hpp不依赖任何第三方库、不需要子项目、不需要复杂的构建系统纯 C11 编写几乎无需调整编译器标志或工程设置。严肃的测试。官方宣称对全部代码含所有异常路径做了单元测试覆盖并通过 Valgrind、Clang Sanitizers 检查内存泄漏另有 OSS-Fuzz 对各解析器进行持续模糊测试项目遵循 Core Infrastructure InitiativeCII最佳实践。同时文档也坦诚列出了非首要目标这有助于你选型时建立正确预期内存效率并非极致。每个 JSON 对象开销约为一个指针联合体的最大尺寸加一个枚举元素1 字节。默认泛化使用std::string存字符串、int64_t/uint64_t/double存数字、std::map存对象、std::vector存数组、bool存布尔值。若需要定制可对泛化类basic_json传入自定义模板参数。速度并非最快。存在更快的解析器但如果你的目标是用一个头文件快速给工程加上 JSON 支持那么会用std::vector和std::map就能上手。仓库内的实际集成方式在 DB4S 工程中该库以随附第三方源码的形式落地整个库位于 libs/json 目录包含 json.hpp、CMakeLists.txt、ChangeLog.md、README.md 与 LICENSE.MIT。根 CMakeLists.txt 通过一条target_include_directories将其作为系统私有包含目录加入编译target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE ${CMAKE_CURRENT_LIST_DIR}/libs/json)随后源码中直接以尖括号包含头文件并取别名即可使用#include json.hpp // 方便起见 using json nlohmann::json; using ordered_json nlohmann::ordered_json;上述用法分别出现在 src/ExportDataDialog.cpp 与 src/EditDialog.cpp 中。注意官方 README 的示例使用#include nlohmann/json.hpp而 DB4S 将头文件平铺在libs/json目录下因此实际包含形式为json.hpp——这是集成方式上的一个细节差异二选一取决于头文件在包含路径中的摆放层级。核心用法一JSON 作为一等数据类型假设要构造如下 JSON 对象{ pi: 3.141, happy: true, name: Niels, nothing: null, answer: { everything: 42 }, list: [1, 0, 2], object: { currency: USD, value: 42.99 } }两种写法等价且全程无需告知编译器目标 JSON 类型// 写法一逐键赋值隐式把 j 升级为 object json j; j[pi] 3.141; // 存储为 double j[happy] true; // 存储为 bool j[name] Niels; // 存储为 std::string j[nothing] nullptr; // 存储为 null j[answer][everything] 42; // 对象内嵌对象 j[list] { 1, 0, 2 }; // 存储为 std::vector初始化列表 j[object] { {currency, USD}, {value, 42.99} }; // 键值对初始化列表 // 写法二整体初始化列表构造 json j2 { {pi, 3.141}, {happy, true}, {name, Niels}, {nothing, nullptr}, {answer, { {everything, 42} }}, {list, {1, 0, 2}}, {object, { {currency, USD}, {value, 42.99} }} };若想显式表达边界情况可使用工厂函数json empty_array_explicit json::array(); // [] json empty_object_implicit json({}); // {} json empty_object_explicit json::object(); // {} json array_not_object json::array({ {currency, USD}, {value, 42.99} }); // 注意上例是键值对组成的数组即 [[currency,USD],[value,42.99]]核心用法二序列化 / 反序列化字符串与字面量后缀给字符串字面量追加_json后缀即可完成反序列化解析json j { \happy\: true, \pi\: 3.141 }_json; // 用原始字符串字面量更易读 auto j2 R( { happy: true, pi: 3.141 } )_json; // 显式解析 auto j3 json::parse(R({happy: true, pi: 3.141}));关键陷阱不加_json后缀时字符串不会被解析而只是作为 JSON 字符串值存储。即json j { \happy\: true, \pi\: 3.141 }存储的是字符串本体而非对象。序列化使用dump()传入缩进空格数即可美化输出std::string s j.dump(); // {happy:true,pi:3.141} std::cout j.dump(4) std::endl; // { // happy: true, // pi: 3.141 // }注意区分取字符串值与序列化json j_string this is a string; auto cpp_string j_string.getstd::string(); // 取回字符串值 std::string cpp_string2; j_string.get_to(cpp_string2); // 取回写入既有变量 std::string serialized_string j_string.dump(); // 显式 JSON 序列化库仅支持 UTF-8若以其他编码存入字符串调用dump()可能抛异常除非使用json::error_handler_t::replace或json::error_handler_t::ignore错误处理器。流文件 / 字符串流流操作符适用于任何std::istream/std::ostream子类json j; std::cin j; // 从标准输入解析 std::cout j; // 序列化到标准输出 std::cout std::setw(4) j std::endl; // setw 被重载用于设置缩进 // 文件读写 std::ifstream i(file.json); json j; i j; std::ofstream o(pretty.json); o std::setw(4) j std::endl;文档特别提醒为此类使用场景设置failbit异常位并不合适会因为库内的noexcept说明符导致程序终止。迭代器区间与自定义数据源可以从任意value_type 为 1/2/4 字节整型的迭代器容器解析分别按 UTF-8/UTF-16/UTF-32 解释std::vectorstd::uint8_t v {t, r, u, e}; json j json::parse(v.begin(), v.end()); // 也可省略区间 json j2 json::parse(v);由于parse接受任意迭代器区间你可以实现LegacyInputIterator概念提供自定义数据源如从自定义容器逐字符读取这是网络流、加密流等场景的扩展点。SAX 接口事件驱动解析除构建 DOM 外库还提供 SAX 风格解析接口回调函数包括bool null(); bool boolean(bool val); bool number_integer(number_integer_t val); bool number_unsigned(number_unsigned_t val); bool number_float(number_float_t val, const string_t s); bool string(string_t val); bool binary(binary_t val); bool start_object(std::size_t elements); bool end_object(); bool start_array(std::size_t elements); bool end_array(); bool key(string_t val); bool parse_error(std::size_t position, const std::string last_token, const detail::exception ex);每个回调的返回值决定解析是否继续。使用方法分三步实现 SAX 接口可继承nlohmann::json_saxjson→ 创建处理对象 → 调用bool json::sax_parse(input, my_sax)。注意sax_parse只返回最后一个 SAX 事件的结果不返回json值解析出错时不抛异常由你的parse_error实现决定如何处理。内部 DOM 解析器json_sax_dom_parser与合法性检查器json_sax_acceptor都构建在这套 SAX 接口之上。核心用法三STL 式访问json类满足ReversibleContainer要求行为与 STL 容器一致// 数组push_back / emplace_back / 迭代 / 比较 json j; j.push_back(foo); j.push_back(1); j.push_back(true); j.emplace_back(1.78); for (json::iterator it j.begin(); it ! j.end(); it) std::cout *it \n; for (auto element : j) // 基于范围的 for std::cout element \n; j R([foo, 1, true, 1.78])_json; // true j.size(); // 4 j.empty(); // false j.type(); // json::value_t::array j.clear(); // 便捷类型检查 j.is_null(); j.is_boolean(); j.is_number(); j.is_object(); j.is_array(); j.is_string(); // 对象下标 / emplace / 键值迭代 json o; o[foo] 23; o[bar] false; o[baz] 3.141; o.emplace(weather, sunny); for (auto el : o.items()) std::cout el.key() : el.value() \n; // C17 结构化绑定 for (auto [key, value] : o.items()) std::cout key : value \n; // 查找与删除 if (o.contains(foo)) { /* 存在 */ } if (o.find(foo) ! o.end()) { /* 存在 */ } int foo_present o.count(foo); // 1 o.erase(foo);核心用法四STL 容器转换所有值类型可构造成 JSON 的序列容器std::array、std::vector、std::deque、std::forward_list、std::list可直接构造 JSON 数组std::set等关联容器同样适用但数组元素顺序取决于容器内部排序std::vectorint c_vector {1, 2, 3, 4}; json j_vec(c_vector); // [1, 2, 3, 4] std::dequedouble c_deque {1.2, 2.3, 3.4, 5.6}; json j_deque(c_deque); // [1.2, 2.3, 3.4, 5.6] std::listbool c_list {true, true, false, true}; json j_list(c_list); // [true, true, false, true] std::setstd::string c_set {one, two, three, four, one}; json j_set(c_set); // 仅一个 one[four,one,three,two]键值容器std::map、std::multimap、std::unordered_map、std::unordered_multimap构造 JSON 对象std::mapstd::string, int c_map { {one, 1}, {two, 2}, {three, 3} }; json j_map(c_map); // {one:1,three:3,two:2} std::unordered_mapconst char*, double c_umap { {one, 1.2}, {two, 2.3}, {three, 3.4} }; json j_umap(c_umap); // {one:1.2,two:2.3,three:3.4}注意 multimap 系列在 JSON 对象中只保留一个键值取决于容器内部顺序。核心用法五JSON Pointer、JSON Patch 与 Merge PatchJSON PointerRFC 6901用于寻址结构化值JSON PatchRFC 6902用于描述两个 JSON 值之间的差异类似 Unix 的 patch/diffjson j_original R({ baz: [one, two, three], foo: bar })_json; j_original[/baz/1_json_pointer]; // two —— JSON Pointer 下标访问 json j_patch R([ { op: replace, path: /baz, value: boo }, { op: add, path: /hello, value: [world] }, { op: remove, path: /foo} ])_json; json j_result j_original.patch(j_patch); // { baz: boo, hello: [world] } // 计算两个 JSON 值的差异 json::diff(j_result, j_original);JSON Merge PatchRFC 7386以贴近被修改文档的语法描述变更null值表示删除键json j_document R({ a: b, c: { d: e, f: g } })_json; json j_patch R({ a:z, c: { f: null } })_json; j_document.merge_patch(j_patch); // { a: z, c: { d: e } } —— f 被 null 删除d 保留隐式转换与建议支持的标量类型可隐式转换到JSON 值但文档强烈建议不要从 JSON 值隐式转换回原生类型而是使用getT()/get_to()// 推荐 auto s2 js.getstd::string(); auto b2 jb.getbool(); auto f jn.getdouble(); // 不推荐从 JSON 隐式转换 std::string s3 js; double f2 jb;可通过在包含json.hpp前定义JSON_USE_IMPLICIT_CONVERSIONS为0关闭隐式转换使用 CMake 时则设置选项JSON_ImplicitConversions为OFF。另外注意char不会被自动转换为 JSON 字符串而是整数ASCII 码值要存字符串需显式构造char ch A; // ASCII 65 json j_default ch; // 存整数 65 json j_string std::string(1, ch); // 存字符串 A任意自定义类型转换手动 to_json / from_json假设要序列化结构体ns::person最朴素的写法是逐字段拷贝但更优雅的方式是提供两个函数必须在类型的命名空间中可以是全局命名空间using json nlohmann::json; namespace ns { struct person { std::string name; std::string address; int age; }; void to_json(json j, const person p) { j json{{name, p.name}, {address, p.address}, {age, p.age}}; } void from_json(const json j, person p) { j.at(name).get_to(p.name); j.at(address).get_to(p.address); j.at(age).get_to(p.age); } } ns::person p {Ned Flanders, 744 Evergreen Terrace, 60}; json j p; // 自动调用 to_json auto p2 j.getns::person(); // 自动调用 from_json要点与坑to_json/from_json必须位于类型所在命名空间否则库无法通过 ADL 找到这些函数在每次使用转换处都必须可见含对应头文件getyour_type()要求类型DefaultConstructible后续有绕过方法from_json内请用at()而非operator[]——键不存在时at()抛可捕获的异常而operator[]是未定义行为STL 类型如std::vector的序列化/反序列化已内置无需额外编写。宏简化NON_INTRUSIVE / INTRUSIVENLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)放在类/结构体所在命名空间中NLOHMANN_DEFINE_TYPE_INTRUSIVE(...)放在类内部可访问私有成员。两者都要求 JSON 对象做序列化载体、成员名做对象键namespace ns { NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) } namespace ns { class address { private: std::string street; int housenumber; int postcode; public: NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) }; }第三方类型特化 adl_serializer默认序列化器是nlohmann::adl_serializerADL 实参依赖查找。处理boost::optional、std::filesystem::path等无法侵入其命名空间的类型时可在nlohmann命名空间内特化adl_serializernamespace nlohmann { template typename T struct adl_serializerboost::optionalT { static void to_json(json j, const boost::optionalT opt) { j (opt boost::none) ? nullptr : static_castjson(*opt); } static void from_json(const json j, boost::optionalT opt) { opt j.is_null() ? boost::none : j.getT(); } }; }非默认构造/不可拷贝类型若类型满足 MoveConstructible可特化adl_serializer并提供单参from_json返回类型namespace nlohmann { template struct adl_serializermove_only_type { static move_only_type from_json(const json j) { return {j.getint()}; } // 注意必须同时提供 to_json否则该类型无法转回 JSON static void to_json(json j, move_only_type t) { j t.i; } }; }自写序列化器进阶可自定义序列化器示例只接受sizeof(T) 32的类型。关键要求使用不同于nlohmann::json的basic_json别名最后一个模板参数是JSONSerializer、在全部to_json/from_json中使用该别名、需要 ADL 时显式using nlohmann::to_json;/using nlohmann::from_json;。文档警告重新实现序列化器时若内部再调用j value会形成自递归可能栈溢出务必小心。枚举转换默认枚举值按整数序列化。但若枚举在数据序列化后发生重排反序列化会得到未定义/非预期值因此可用NLOHMANN_JSON_SERIALIZE_ENUM宏把枚举映射为字符串enum TaskState { TS_STOPPED, TS_RUNNING, TS_COMPLETED, TS_INVALID-1, }; // 映射为字符串宏必须在枚举的命名空间含全局内声明 NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, { {TS_INVALID, nullptr}, {TS_STOPPED, stopped}, {TS_RUNNING, running}, {TS_COMPLETED, completed}, }) json j TS_STOPPED; assert(j stopped); json j3 running; assert(j3.getTaskState() TS_RUNNING); json jPi 3.14; assert(jPi.getTaskState() TS_INVALID); // 未定义值回退到映射表首项两个要点未定义 JSON 值回退到映射表第一个条目请谨慎选择默认项枚举或 JSON 值在映射表中重复出现时取自上而下第一个匹配项。二进制格式BSON、CBOR、MessagePack 与 UBJSONJSON 不紧凑不适合网络传输。库内置四种二进制格式的编解码均以std::vectorstd::uint8_t为载体并支持 roundtripjson j R({compact: true, schema: 0})_json; std::vectorstd::uint8_t v_bson json::to_bson(j); json j_from_bson json::from_bson(v_bson); std::vectorstd::uint8_t v_cbor json::to_cbor(j); json j_from_cbor json::from_cbor(v_cbor); std::vectorstd::uint8_t v_msgpack json::to_msgpack(j); json j_from_msgpack json::from_msgpack(v_msgpack); std::vectorstd::uint8_t v_ubjson json::to_ubjson(j); json j_from_ubjson json::from_ubjson(v_ubjson);BSON、CBOR字节串、MessagePackbin/ext/fixext中的二进制类型默认存为std::vectorstd::uint8_t// CBOR 字节串载荷 0xCAFE std::vectorstd::uint8_t v {0x42, 0xCA, 0xFE}; json j json::from_cbor(v); j.is_binary(); // true auto binary j.get_binary(); binary.has_subtype(); // falseCBOR 无二进制子类型 binary.size(); // 2 binary[0]; // 0xCA binary.set_subtype(0x10); // 设置子类型 auto cbor json::to_msgpack(j); // 0xD5 (fixext2), 0x10, 0xCA, 0xFE在 DB Browser for SQLite 中的真实应用nlohmann/json 并不是 DB4S 的附属装饰而是查询结果导出与单元格数据编辑两条功能线的核心依赖。查询结果导出 JSONExportDataDialogsrc/ExportDataDialog.cpp 的exportQueryJson()演示了SQLite 行 → JSON的完整流水线先sqlite3_prepare_v2准备 SQL 语句逐行sqlite3_step取结果再按列类型写入json_rowSQLITE_INTEGER→json_row[column_name] content;写入qint64SQLITE_FLOAT→ 写入doubleSQLITE_NULL→json_row[column_name] nullptr;对应 JSONnullSQLITE_TEXT→ 经 UTF-8 转换后写入std::stringSQLITE_BLOB→ Base64 编码为字符串后写入每行用json_table.push_back(json_row)聚合为数组最后通过json_table.dump(ui-checkPrettyPrint-isChecked() ? 4 : -1)输出——勾选美化打印时缩进 4 个空格否则用-1输出紧凑单行。这正是官方 README 中dump(indent)参数语义的直接落地。相关 UI 状态还会写入设置项exportjson/prettyprint见 src/ExportDataDialog.cpp。单元格 JSON 校验与格式化EditDialogsrc/EditDialog.cpp 在 JSON 编辑器模式下用json::parse解析单元格文本并捕获json::parse_error处理非法输入为保留键的插入顺序它还使用ordered_json类型见 src/EditDialog.cpp。此外 src/EditDialog.cpp 通过json::parse(cellData, nullptr, false)判断数据是否为合法 JSON 且非数字用于数据类型探测在 src/EditDialog.cpp 中JSON 数据经jsonDoc.dump(4)缩进后重新写入单元格实现格式化 JSON功能。这两处源码可以当作该库在生产级桌面应用中的参考范本解析用异常捕获保障健壮性、序列化用dump(indent)控制输出形态、ordered_json应对键序敏感场景。编译器支持文档列出的已知可用编译器范围以文档撰写时期为准GCC 4.8–11.0、Clang 3.4–13.0、Apple Clang 9.1–12.4、Intel C Compiler 17.0.2、MSVC 2015/2017/2019Build Tools 14.0.25123.0 起。注意事项GCC 4.8 存在 [57824] 号 bug多行原始字符串不能作为宏参数请勿在该编译器下于宏中直接使用多行原始字符串Android 默认使用过旧编译器/库时可在Application.mk中设置APP_STL : c_shared、NDK_TOOLCHAIN_VERSION : clang3.6、APP_CPPFLAGS -frtti -fexceptionsMinGW 或 Android SDK 下若报to_string is not a member of std属编译器自身问题而非库问题不受支持的 GCC/Clang 版本会被#error指令拒绝编译可通过定义JSON_SKIP_UNSUPPORTED_COMPILER_CHECK关闭该检查但此情形下官方不提供支持。工程集成方式直接使用头文件json.hpp是唯一必需文件使用前开启 C11如 GCC/Clang 加-stdc11。也可使用json_fwd.hpp做前置声明安装它需在 CMake 中设置-DJSON_MultipleHeadersON。CMakenlohmann_json::nlohmann_json接口目标会自动填充INTERFACE_INCLUDE_DIRECTORIES与 C11 所需的INTERFACE_COMPILE_FEATURES。外部依赖find_packagefind_package(nlohmann_json 3.2.0 REQUIRED) add_library(foo ...) target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)内嵌子目录set(JSON_BuildTests OFF CACHE INTERNAL ) add_subdirectory(nlohmann_json) add_library(foo ...) target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)FetchContentCMake ≥ 3.11include(FetchContent) FetchContent_Declare(json GIT_REPOSITORY https://github.com/nlohmann/json.git GIT_TAG v3.7.3) FetchContent_GetProperties(json) if(NOT json_POPULATED) FetchContent_Populate(json) add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) endif() target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)文档提示完整源码仓库体积庞大含基准测试数据集可用更精简的镜像仓库或随 release 发布的include.zip作为依赖源。同时支持外部与内嵌可在顶层用option(FOO_USE_EXTERNAL_JSON ...)开关配合thirdparty/CMakeLists.txt中if(FOO_USE_EXTERNAL_JSON) find_package(...) else() add_subdirectory(...) endif()的模式而链接目标始终统一为nlohmann_json::nlohmann_json。包管理器与 pkg-config文档覆盖了主流包管理器Homebrewbrew install nlohmann-json尝鲜用--HEAD、Mesonsubproject 或meson wrap install nlohmann_json、Conannlohmann_json/x.y.z、Spack、Hunter、Buckaroo、vcpkgvcpkg install nlohmann-json、cgetcget install nlohmann/json、CocoaPods、NuGet、conda-forgeconda install -c conda-forge nlohmann_json、MSYS2pacman -S mingw-w64-x86_64-nlohmann-json、MacPortssudo port install nlohmann-json、build2depends: nlohmann-json、wsjcpp、CPM.cmake 等。裸 Makefile 可借助 pkg-configpkg-config nlohmann_json --cflagsMeson 中则用dependency(nlohmann_json, required: true)获取系统级依赖。JSON 语义细节与陷阱字符编码仅支持UTF-8输入这也是 RFC 8259 规定的 JSON 默认编码std::u16string/std::u32string可按 UTF-16/UTF-32 解析但不支持从文件等输入容器读取Latin-1、ISO 8859-1 等其他编码不支持会产生解析/序列化错误Unicode 非字符不会被替换无效代理对如孤立的\uDEAD会触发解析错误存储的字符串为 UTF-8默认std::string的size()返回字节数而非字符数宽字符串std::wstring需先转成 UTF-8std::string再存储。注释支持库默认不支持JSON 注释。文档援引了三点理由注释不属于 JSON 规范JSON 不是 JavaScriptDouglas Crockford 曾明确移除注释以免其被用于承载解析指令、破坏互操作性部分实现加注释而部分不加会危及互操作。如需处理带注释的配置文件可先经 JSMin 类工具预处理或调用json::parse(input, nullptr, true /* ignore_comments */)将//与/* */注释当空白忽略。对象键顺序默认不保留对象元素的插入顺序JSON 规范将对象定义为无序集合。需要保留顺序时可使用nlohmann::ordered_json——这正是 DB4S 的 src/EditDialog.cpp 所采用的做法也可接入tsl::ordered_map或nlohmann::fifo_map等有序容器。内存释放文档声明经 Valgrind 与 ASAN 检查无内存泄漏。若解析程序未立即归还内存多与 glibc 的分配阈值缓存策略有关大量低于阈值的小分配不会立即归还操作系统这属于运行时库行为而非本库泄漏。其他关键编译期行为代码内含大量调试断言可定义NDEBUG关闭。尤其operator[]对 const 对象是非检查访问键不存在时行为未定义类似解引用空指针断言开启时会触发断言失败不确定键是否存在时请使用at()。也可定义JSON_ASSERT(x)替换assert(x)JSON 规范未规定数字的精确 C 类型库会自动选择最合适类型double可能被选中若调用方解除了浮点异常掩码某些罕见情况下会触发浮点异常属调用方问题可用-fno-rtti编译无需运行时类型识别异常可被关闭使用-fno-exceptions或定义JSON_NOEXCEPTION异常将替换为abort()并可分别用JSON_THROW_USER/JSON_TRY_USER/JSON_CATCH_USER覆盖 throw/try/catch。注意JSON_THROW_USER应离开当前作用域抛出或 abort否则继续执行可能产生未定义行为。运行单元测试从源码构建并运行测试mkdir build cd build cmake .. -DJSON_BuildTestsOn cmake --build . ctest --output-on-failure注意事项原文照录并加以说明ctest阶段会从外部仓库下载多个 JSON 测试数据文件若策略禁止下载可自行下载后通过-DJSON_TestDataDirectorypath传入从而无需联网以压缩包方式获取的源码没有 Git 元数据cmake_fetch_content_configure测试会失败可执行ctest -LE git_required跳过部分测试会改动已安装文件导致过程不可复现可执行ctest -LE not_reproducible跳过同时排除两组标签需用cmake -LE not_reproducible|git_requiredIntel 编译器默认使用不安全的浮点优化可能致测试失败请加/fp:precise。许可证与第三方成分本库采用 MIT License版权 2013–2021Niels Lohmann详见 libs/json/LICENSE.MIT。库内还包含以下第三方成分Bjoern Hoehrmann 的 UTF-8 解码器MIT、Florian Loitsch 的 Grisu2 算法修改版MIT、Evan Nemerson 的 HedleyCC0-1.0、Google Abseil 的部分代码Apache 2.0。构建与质量保障依赖大量第三方工具amalgamate、AFL/libFuzzer、Valgrind、Clang Sanitizers、doctest、Doxygen、OSS-Fuzz、Coverity 等。小结nlohmann/json 以单头文件 纯 C11 STL 化体验三个特征成为 C 项目中接入 JSON 的低摩擦方案。通过本文你可以用_json字面量、parse/dump完成双向转换用 STL 式 API 增删改查用to_json/from_json、NLOHMANN_DEFINE_TYPE_*宏和adl_serializer特化打通自定义类型用四种二进制格式提升网络传输效率并在 DB4S 的 ExportDataDialog 与 EditDialog 源码中看到它在真实产品中的调用范式。若需查阅更完整的能力清单仓库内还保留了 libs/json/ChangeLog.md 供追溯各版本演进。赞分享数据库数据库客户端桌面应用【免费下载链接】sqlitebrowserOfficial home of the DB Browser for SQLite (DB4S) project. Previously known as SQLite Database Browser and Database Browser for SQLite. Website at:项目地址https://gitcode.com/gh_mirrors/sq/sqlitebrowser点击查看免费下载相关推荐nlohmann-json 现代 C JSON 库实战指南从单头文件集成到 MongoDB 源码级应用nlohmann json 现代 C JSON 库实战指南从单头文件集成到 MongoDB 源码级应用 本文以 MongoDB 仓库中内置的第三方库 nl数据库文档数据库后端JSON for Modern Cnlohmann/json深度解析单头文件 C11 JSON 库的核心用法与工程集成JSON for Modern Cnlohmann/json深度解析单头文件 C11 JSON 库的核心用法与工程集成 本指南围绕本仓库所收录的序列化探索现代C的JSON库nlohmann/json探索现代C的JSON库nlohmann/json 在现代软件开发中JSON作为一种轻量级的数据交换格式广泛应用于各种系统和平台之间的数据传输。对于C序列化上一篇5步掌握超星学习通自动化签到从零到精通的完整实践指南下一篇企业微信开发终极指南从零构建组织架构与消息推送系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表