结论:小项目、嵌入式或需人工编辑时选ini;有嵌套结构、多语言协作或工具链支持时选json。ini语法极简、解析轻量、注释友好,但不支持嵌套与类型;json支持复杂数据结构和自动类型推导,但容错性差、对格式敏感。

配置文件格式选 INI 还是 JSON?别只看语法简洁
直接说结论:小项目、嵌入式或需人工编辑的场景,优先用 INI;有嵌套结构、多语言协作或已有工具链支持,选 JSON。C++ 没原生支持,得靠库,但选型影响后续加载逻辑和错误处理粒度。
INI 的优势在于人眼可读性强、解析轻量(比如用 inih 库只需两个 C 函数),但不支持嵌套、数组和类型标注;JSON(如用 nlohmann/json)天然支持嵌套对象和自动类型推导,但单个配置项出错容易导致整个文件解析失败,且对空格/逗号更敏感。
- 若配置项全是键值对、无层级(如
port=8080、log_level=debug),INI更省心 - 若需表达
database.servers=[{"host":"a","port":3306},{"host":"b","port":3307}],JSON是唯一现实选择 - Windows 下注意
INI文件可能含 BOM,fopen读取后需跳过0xEF 0xBB 0xBF
用 nlohmann/json 加载 JSON 配置时,如何避免 parse_error 崩溃
默认情况下,json::parse() 遇到非法 JSON 会抛 json::parse_error 异常,而很多 C++ 项目禁用异常——这会导致未定义行为或静默崩溃。必须显式处理。
正确做法是用 json::accept() 预检,再用 json::parse() 的非抛出重载:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
std::ifstream f("config.json");
std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
if (!nlohmann::json::accept(content)) {
// 记录具体位置:content.substr(0, 100) + "..."
return false;
}
auto j = nlohmann::json::parse(content, nullptr, false); // 第三个参数为 false 表示不抛异常
if (j.is_discarded()) {
// 解析失败,j 为空对象,可查 error_handler 或手动定位
return false;
}</char></char>
-
json::parse(content, nullptr, false)的第二个参数是std::function类型的错误处理器,传nullptr即使用默认静默处理 - 不要依赖
j.empty()判断失败——空 JSON 对象{}合法且不为空,要用j.is_discarded() - 调试时把出错前 50 字符打印出来,比只报行号有用得多
手写 INI 解析器时,哪些边界情况会让 std::getline 失效
很多教程直接用 std::getline 逐行读,但实际中常见三类失效:
- Windows 换行符
\r\n导致行尾多出\r,后续find('=')匹配失败——读完每行后要手动erase(std::remove(line.begin(), line.end(), '\r'), line.end()) - 注释行以
;或#开头,但有人写成key=value # comment,此时不能整行跳过,得先 trim 再找第一个= - 值含等号(如
url=https://example.com?a=b&c=d),必须从右往左找最后一个=,否则截断错误
更稳妥的做法是:用 std::string_view 切分,跳过空白和注释,再用 sv.find_last_of('=') 定位键值分界点。这样既避免内存拷贝,也绕开 \r 干扰。
配置热重载时,stat() 和 inotify 哪个更适合生产环境
开发阶段轮询 stat() 简单直接;但生产环境高并发服务里,每秒检查一次配置文件 mtime 会造成不必要的系统调用开销,且延迟不可控。Linux 下应优先用 inotify。
-
inotify可监听IN_MODIFY事件,触发即 reload,无延迟、无轮询消耗 - 注意
inotify实例数受/proc/sys/fs/inotify/max_user_instances限制,长期运行服务需捕获inotify_init()返回 -1 并降级为 stat 轮询 - Windows 对应方案是
FindFirstChangeNotification,但 API 更复杂,跨平台项目建议封装统一接口,而非硬编码#ifdef _WIN32
真正容易被忽略的是:reload 后旧配置对象的生命周期管理。如果其他线程正拿着老配置指针访问,直接 delete 会导致 use-after-free——必须用原子指针交换或引用计数,而不是简单 new/delete。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










