应使用 inih 库而非手写解析器,因其轻量、稳定、无依赖;std::ifstream 仅能读行,需配合 getline 手动处理注释、section、key-value 等细节,避免 stringstream 截断带空格的值。

用 std::ifstream 读 ini 文件,别直接 parse
纯 C++ 标准库不支持 ini 解析,std::ifstream 只能读文本行,不能自动识别 section 或 key-value。硬写 parser 容易漏掉注释、空行、引号包裹值、等号前后空格这些细节。
实操建议:
- 用
std::getline逐行读,自己跳过//和#开头的注释行 - 遇到
[section]时更新当前 section 名(去掉方括号和空格) - 对普通行用
find('=')找第一个等号,左侧 trim 后是 key,右侧 trim 后是 value - 别用
std::stringstream >>解析 value——它会把"hello world"截成"hello",改用substr+ 手动去引号
选 inih 而不是手写,因为它的 INIReader 真的轻
inih 是 C 写的单头文件库,C++ 项目里 #include 就能用,没依赖、无宏污染、不抛异常。比 Boost.Program_options 轻太多,也比自己维护一个 parser 稳定。
常见错误现象:编译报 undefined reference to inih::INIReader::INIReader(std::string const&)——这是因为 inih 的 C++ 封装(INIReader.h)需要对应实现文件(INIReader.cpp),不能只 include 头。
立即学习“C++免费学习笔记(深入)”;
使用场景:
- 配置项少(
- 不需要运行时热重载
- 目标平台不支持 C++17 以上(
inihC++11 兼容)
示例初始化:
inih::INIReader reader("config.ini");
if (reader.ParseError() != 0) {
// 错误处理
}
std::string host = reader.Get("network", "host", "localhost");
XML 用 pugixml,别碰 tinyxml2 的 FirstChildElement 链式调用
pugixml 的 API 更符合直觉:节点查找返回 pugi::xml_node,查不到就是空节点,不用判 null;而 tinyxml2 的 FirstChildElement("x")->FirstChildElement("y") 一旦中间某个环节为空,就会 core dump。
性能影响:pugixml 默认用 DOM 模式加载,小配置(pugi::xml_parse_default | pugi::parse_trim_pcdata 减少内存占用。
容易踩的坑:
-
pugi::xml_document::load_file()返回pugi::xml_parse_result,必须检查.status == pugi::status_ok,否则后续所有child()调用都未定义行为 - XML 中的
&必须写成&,否则pugixml解析失败且错误信息只报 “expected ‘>’”,不提转义问题 - 读取属性值用
attribute("name").as_string(),别用text().as_string()——后者读的是标签体内容
ini 和 XML 选哪个?看部署环境和修改频率
运维人员改配置时,更愿意面对 config.ini 还是 config.xml?答案通常是前者。XML 的缩进、闭合标签、转义规则,在没有编辑器辅助的服务器上极易出错。
但如果你的配置天然带层级(比如日志模块要分 console/file/remote 三套独立参数),XML 的嵌套结构比 ini 的 flat key(如 log.console.level)更易维护。
兼容性提醒:
- Windows 注册表导出、旧版工具生成的 ini 可能含 BOM,
inih不处理,需提前用std::ifstream跳过前 3 字节 - Linux 容器里若用 musl libc(Alpine),
pugixml的某些 locale 相关函数可能失效,建议关闭PUGIXML_NO_XPATH编译选项
最麻烦的其实是混合场景:主配置用 XML,但某几个字段允许用户填 ini 片段(比如自定义脚本参数)。这时候 parser 边界得划清楚,别让 ini 解析器去吃 XML 的尾巴。









