GetPrivateProfileString在Windows下简单但有硬伤:不支持UTF-8路径与编码、无法读空值、跳过含注释行、ANSI处理致中文乱码;推荐跨平台inih库,轻量单头、支持注释与UTF-8原始字节、需注意回调拷贝、重复key处理及转义规则。

Windows平台用GetPrivateProfileString最简单但有硬伤
如果你只在Windows下跑,且Ini文件结构非常简单(无节嵌套、无转义、路径固定),GetPrivateProfileString确实能一行读值:
char buf[256];<br>GetPrivateProfileStringA("database", "host", "localhost", buf, sizeof(buf), "config.ini");
但它不支持UTF-8路径、无法读取空值、遇到注释行(;或#开头)会直接跳过整行——哪怕注释在值后面,比如port=3306 ; mysql port,结果buf里啥也得不到。
更麻烦的是它把所有字符串当ANSI处理,若Ini文件是UTF-8编码(现在几乎默认如此),中文直接变乱码,且函数本身不报错,你得靠肉眼判断输出是否异常。
跨平台方案推荐inih库:轻量、头文件即用、不依赖STL
inih(INI Not Invented Here)是C写的单头文件解析器,C++项目里直接#include "ini.h"就能用,没有编译依赖。它用回调机制逐行解析,天然支持;和#行内注释,且对BOM和UTF-8编码的value字段不做转换——你拿到的就是原始字节,后续用std::string或std::u8string接住即可。
实操要点:
立即学习“C++免费学习笔记(深入)”;
- 定义回调函数时,
section和name参数是const char*,指向内存中连续缓冲区,不要存指针,要拷贝内容 - 若Ini里有重复key(如两个
timeout=30),回调会被触发多次,需自行决定覆盖还是收集 - 空节名(
[ ])和空key名(=value)默认被忽略,如需支持,得改INI_ALLOW_NOSECTIONS宏定义 - 解析失败时不抛异常,返回负值(如
-1表示文件打开失败,-2表示内存不足),必须检查返回值
自己手写解析器要注意和
的处理边界
很多人抄个正则或按行split就开干,结果在Windows路径或日志格式值上翻车。Ini规范允许值中含换行(用转义)和反斜杠(表示字面量),但实际文件里常混用和,且不同编辑器对续行符(结尾)支持不一。
关键判断点:
- 遇到
结尾的行,下一行必须拼接到当前value末尾,且去掉下一行开头的空白——但若下一行是;或#,应视为注释而非续行 -
必须替换成单个,而替换成实际换行符,但
、等非标准转义应原样保留,别擅自扩展 - 双引号包裹的值(如
path="C: emplog.txt")不进行反斜杠转义,这是很多手写解析器漏掉的规则
用std::regex解析Ini?性能差且易匹配错节名
有人想用std::regex一次性匹配[section]或key=value,但正则在C++11/14里编译慢、运行慢,且Ini语法本身不适合正则:节名可含空格([My DB Config]),key可含等号(url=http://a=b/c),value可含方括号(desc=[important])。一个看似简单的^[(.*)]$会把[section] # comment里的# comment也吞进去。
更现实的问题是,std::regex在GCC 7以下版本对Unicode支持极弱,遇到UTF-8编码的节名基本匹配失败;MSVC的std::regex又不支持PCRE的原子组,导致回溯爆炸。真要用正则,建议只做预处理(比如剔除整行注释),核心解析仍用状态机。
复杂点永远在细节:空行是否算分隔、等号前后空白要不要trim、BOM要不要跳过、大小写是否敏感——这些没明确定义的地方,才是实际项目里最耗时间调试的部分。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xitongjiaocheng/125724.html