使用TinyXML2将C++ string保存到XML文件的问题及解决
解决TinyXML2 SetText()与C++ string的兼容问题及结构体数据一致性问题
问题背景
我是C++初学者,在编写控制台程序时遇到TinyXML2的使用困扰:
SetText()方法仅接受char数组类型参数,但我想直接将std::string类型数据保存到XML文件- 定义的
person结构体同时包含std::string和char数组成员:
struct person { int Id = 0; std::string Name; char cname[20]; std::string LastName; char clastname[20]; int Age; };
- 保存时用char数组(如
p.cname)能正常写入XML,但加载时仅给std::string类型的Name赋值,未填充char数组cname,导致再次保存时数据异常。加载代码片段:
XMLElement* p_name = p_person->FirstChildElement("pname"); std::string pname = p_name->GetText(); nPerson.Name = pname;
- 尝试手动将string转为char数组保存时,仅能写入第一个字符,最终通过
pName.c_str()获取const char*传入SetText()解决了保存问题。
可选解决方案
方案1:移除结构体中的char数组,统一用std::string处理
这是最简洁的方案,彻底避免两种字符串类型带来的一致性问题:
- 修改结构体,去掉冗余的char数组:
struct person { int Id = 0; std::string Name; std::string LastName; int Age; };
- 保存时直接传入
string的c_str()结果给SetText():
// 示例保存逻辑 XMLElement* nameElement = doc.NewElement("pname"); nameElement->SetText(personObj.Name.c_str());
- 加载时直接将
GetText()结果赋值给std::string:
XMLElement* p_name = p_person->FirstChildElement("pname"); if (p_name && p_name->GetText()) { personObj.Name = p_name->GetText(); }
这种方案无需维护两种字符串类型,大幅降低出错概率,适合绝大多数场景。
方案2:加载时将string转为char数组,保留原有结构体结构
如果必须保留char数组成员,加载时需要把XML读取到的std::string转存到char数组,注意处理长度限制避免越界:
XMLElement* p_name = p_person->FirstChildElement("pname"); if (p_name && p_name->GetText()) { std::string pname = p_name->GetText(); nPerson.Name = pname; // 最多复制19个字符,预留1个位置给字符串结束符 strncpy(nPerson.cname, pname.c_str(), sizeof(nPerson.cname)-1); // 手动添加结束符,防止出现垃圾数据 nPerson.cname[sizeof(nPerson.cname)-1] = '\0'; }
注意:strncpy不会自动添加字符串结束符,必须手动设置,否则char数组可能出现未定义行为。
关于手动转char数组仅保存第一个字符的问题
之前手动转char数组只保存第一个字符,大概率是因为错误地直接用=赋值char数组(C++不允许这种操作),或者没有正确添加字符串结束符。而std::string::c_str()会返回带正确结束符的const char*,直接传给SetText()就能完整保存字符串。
内容的提问来源于stack exchange,提问作者MatthieuCross
相关产品推荐
相关产品推荐

