我有一个Windows应用程序,其中字符串类型为WCHAR*
。我需要将其转换为char*
以传入C API。我正在使用MultiByteToWideChar
和WideCharToMultiByte
函数来执行转换。
但由于某种原因,转换不合适。我在输出中看到很多胡言乱语。以下代码是this stackoverflow应答中的修改版本。
WCHAR* convert_to_wstring(const char* str)
{
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, (int)strlen(str), NULL, 0);
WCHAR* wstrTo = (WCHAR*)malloc(size_needed);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)strlen(str), wstrTo, size_needed);
return wstrTo;
}
char* convert_from_wstring(const WCHAR* wstr)
{
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)wcslen(wstr), NULL, 0, NULL, NULL);
char* strTo = (char*)malloc(size_needed);
WideCharToMultiByte(CP_UTF8, 0, wstr, (int)wcslen(wstr), strTo, size_needed, NULL, NULL);
return strTo;
}
int main()
{
const WCHAR* wText = L"Wide string";
const char* text = convert_from_wstring(wText);
std::cout << text << "\n";
std::cout << convert_to_wstring("Multibyte string") << "\n";
return 0;
}
答案 0 :(得分:12)
您的转换功能有问题。
MultiByteToWideChar()
的返回值是宽字符数,而非字节数,就像您当前正在处理它一样。调用sizeof(WCHAR)
时,您需要将malloc()
的值加倍。
您也没有考虑返回值不包含空终止符的空格,因为您没有在-1
参数中传递cbMultiByte
。 Read the MultiByteToWideChar()
documentation:
cbMultiByte
[in]
由lpMultiByteStr
参数指示的字符串的大小(以字节为单位)。或者,如果字符串以空值终止,则此参数可以设置为-1。请注意,如果cbMultiByte
为0,则函数将失败。如果此参数为-1,则该函数处理整个输入字符串,包括终止空字符。因此,生成的Unicode字符串具有终止空字符,函数返回的长度包括此字符。
如果此参数设置为正整数,则该函数将精确处理指定的字节数。 如果提供的大小不包含终止空字符,则生成的Unicode字符串不以空值终止,并且返回的长度不包括此字符。
...
返回值
如果成功,则返回写入
lpWideCharStr
指示的缓冲区的字符数。如果函数成功且cchWideChar
为0,则返回值为lpWideCharStr
指示的缓冲区所需的大小,字符。
您不是以null结尾输出字符串。
您的convert_from_wstring()
功能也是如此。 Read the WideCharToMultiByte()
documentation:
cchWideChar
[in]
由lpWideCharStr
表示的字符串的大小(以字符为单位)。或者,如果字符串以空值终止,则此参数可以设置为-1。如果cchWideChar
设置为0,则函数失败。如果此参数为-1,则该函数处理整个输入字符串,包括终止空字符。因此,生成的字符串具有终止空字符,函数返回的长度包括该字符。
如果此参数设置为正整数,则该函数将精确处理指定数量的字符。 如果提供的大小不包含终止空字符,则生成的字符串不以空值终止,并且返回的长度不包括此字符。
...
返回值
如果成功,则返回写入
lpMultiByteStr
指向的缓冲区的字节数。如果函数成功且cbMultiByte
为0,则返回值为lpMultiByteStr
指示的缓冲区所需的大小,以字节为单位。
话虽如此,您的main()
代码正在泄漏已分配的字符串。由于它们已分配malloc()
,因此您需要在使用free()
后将其取消分配:
此外,您无法将WCHAR*
字符串传递给std::cout
。嗯,你可以,但它没有operator<<
用于宽字符串输入,但它确实有一个operator<<
用于void*
输入,所以它最终会输出内存地址 WCHAR*
指向的是,而不是实际的字符。如果要输出宽字符串,请改用std::wcout
。
尝试更像这样的事情:
WCHAR* convert_to_wstring(const char* str)
{
int str_len = (int) strlen(str);
int num_chars = MultiByteToWideChar(CP_UTF8, 0, str, str_len, NULL, 0);
WCHAR* wstrTo = (WCHAR*) malloc((num_chars + 1) * sizeof(WCHAR));
if (wstrTo)
{
MultiByteToWideChar(CP_UTF8, 0, str, str_len, wstrTo, num_chars);
wstrTo[num_chars] = L'\0';
}
return wstrTo;
}
CHAR* convert_from_wstring(const WCHAR* wstr)
{
int wstr_len = (int) wcslen(wstr);
int num_chars = WideCharToMultiByte(CP_UTF8, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
CHAR* strTo = (CHAR*) malloc((num_chars + 1) * sizeof(CHAR));
if (strTo)
{
WideCharToMultiByte(CP_UTF8, 0, wstr, wstr_len, strTo, num_chars, NULL, NULL);
strTo[num_chars] = '\0';
}
return strTo;
}
int main()
{
const WCHAR* wText = L"Wide string";
const char* text = convert_from_wstring(wText);
std::cout << text << "\n";
free(text);
const WCHAR *wtext = convert_to_wstring("Multibyte string");
std::wcout << wtext << "\n";
free(wtext);
return 0;
}
话虽如此,您确实应该使用std::string
和std::wstring
代替char*
和wchar_t*
来改善内存管理:
std::wstring convert_to_wstring(const std::string &str)
{
int num_chars = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
std::wstring wstrTo;
if (num_chars)
{
wstrTo.resize(num_chars);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstrTo[0], num_chars);
}
return wstrTo;
}
std::string convert_from_wstring(const std::wstring &wstr)
{
int num_chars = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL);
std::string strTo;
if (num_chars > 0)
{
strTo.resize(num_chars);
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), &strTo[0], num_chars, NULL, NULL);
}
return strTo;
}
int main()
{
const WCHAR* wText = L"Wide string";
const std::string text = convert_from_wstring(wText);
std::cout << text << "\n";
const std::wstring wtext = convert_to_wstring("Multibyte string");
std::wcout << wtext << "\n";
return 0;
}
如果您使用的是C ++ 11或更高版本,请查看std::wstring_convert
类以便在UTF字符串之间进行转换,例如:
std::wstring convert_to_wstring(const std::string &str)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> conv;
return conv.from_bytes(str);
}
std::string convert_from_wstring(const std::wstring &wstr)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> conv;
return conv.to_bytes(wstr);
}
如果您需要与基于char*
/ wchar_t*
的其他代码进行互动,std::string
作为接受char*
输入的构造函数和c_str()
可用于char*
输出的方法,std::wstring
和wchar_t*
也是如此。
答案 1 :(得分:0)
在Windows上执行此操作的最简单方法是使用
中的_bstr_
#include <comdef.h> // _bstr_t
#include <string>
#include <iostream>
std::wstring convert_to_wstring(const char* str)
{
return _bstr_t(str);
}
std::string convert_from_wstring(const WCHAR* wstr)
{
return _bstr_t(wstr);
}
int main()
{
const auto text = convert_from_wstring(L"Wide string");
const auto wide_text = convert_to_wstring("Multibyte string");
return 0;
}
另外,请注意返回std::wstring
和std::string
会更容易。