WideCharToMultiByte的一次错误用法
windows编程中做字符串转换的一次错误总结
在windows客户端开发时,我想通过windows的WideCharToMultiByte实现将std::wstring转为std::string的功能,但是将输出的std::string转给sqlpp11时发生了报错。
报错分析
Sqlite3 error: Could not prepare statement: unrecognized token: "'123456" (statement was >>INSERT INTO account (id,avatar,name) VALUES('123456
这段报错说明,我传入的sql语句发生了截断,往前分析就是一个普通的wstring类型往string类型做了一次转换。
错误代码
下边这段代码是造成问题的代码
std::string WstringToString(const std::wstring& wstr) {
if (wstr.empty()) return "";
// 获取所需缓冲区大小(不包括 null 终止符)
int bufferSize = WideCharToMultiByte(
CP_UTF8,
0,
wstr.c_str(),
//static_cast<int>(wstr.size()), // 使用实际长度,不是 -1
-1,
nullptr,
0,
nullptr,
nullptr
);
if (bufferSize == 0) {
throw std::runtime_error("宽字符转多字节失败");
}
std::string str;
str.resize(bufferSize); // 只分配必要长度,不填充 0
int result = WideCharToMultiByte(
CP_UTF8,
0,
wstr.c_str(),
//static_cast<int>(wstr.size()),
-1,
&str[0],
bufferSize,
nullptr,
nullptr
);
if (result == 0) {
throw std::runtime_error("宽字符转多字节失败");
}
return str;
}
修复后代码
只要把默认的-1换成实际的长度即可。当传入-1的时候,他会把全部的缓冲区读进去,包括字符串结尾的’\0‘。最后输出的字符串也就包括了结尾的\0,导致sql识别异常。
std::string WstringToString(const std::wstring& wstr) {
if (wstr.empty()) return "";
// 获取所需缓冲区大小(不包括 null 终止符)
int bufferSize = WideCharToMultiByte(
CP_UTF8,
0,
wstr.c_str(),
static_cast<int>(wstr.size()), // 使用实际长度,不是 -1
nullptr,
0,
nullptr,
nullptr
);
if (bufferSize == 0) {
throw std::runtime_error("宽字符转多字节失败");
}
std::string str;
str.resize(bufferSize); // 只分配必要长度,不填充 0
int result = WideCharToMultiByte(
CP_UTF8,
0,
wstr.c_str(),
static_cast<int>(wstr.size()),
&str[0],
bufferSize,
nullptr,
nullptr
);
if (result == 0) {
throw std::runtime_error("宽字符转多字节失败");
}
return str;
}