如何将LPCWSTR转换为wchar_t*并保持编码页一致?
LPCWSTR转wchar_t*后编码页值不一致的解决方法
问题场景
要把LPCWSTR类型的数据转成wchar_t*,试过几种方法都能转,但获取编码页时数值不对。代码和现象如下:
std::string ChineseCharacter(LPCWSTR Data) // Data的值是L"丂" { CString sHexValue = ""; std::wstring sData(Data); wchar_t* str1 = (wchar_t*)Data; //wchar_t* str2 = (wchar_t*)_wcsdup(sData.c_str()); wchar_t* str3 = (wchar_t*)(L"丂"); // 对应GB18030编码0x81 0x40,符合需求 for (int i = 0; i < 4; i++) { sHexValue2.Format("%02x", str1[i]);// 输出4E02,不符合需求 //sHexValue2.Format("%02x", str2[i]);// 输出4E02,不符合需求 sHexValue2.Format("%02x", str3[i]);// 第一次循环输出81,第二次输出40,符合需求 } }
监视窗口显示:
str1= L"丂" str3= L"@"
核心疑问:怎么把Data的值转成wchar_t*,让它和硬编码的L"丂"效果完全一致?
问题本质
你混淆了UTF-16宽字符和GB18030多字节编码的存储逻辑:
- str1直接转的是系统默认的UTF-16宽字符,"丂"的UTF-16编码是
0x4E02,所以循环取到的是这个宽字符的字节值 - 硬编码的
L"丂"在你的编译环境里,被编译器按GB18030编码解析了——"丂"的GB18030编码是两个字节0x81和0x40,编译器把这两个字节分别塞到两个wchar_t变量的低8位里,所以str3的实际内容是0x0081和0x0040,对应显示成@(因为0x40是ASCII的@)
解决方案
要实现需求,得把UTF-16的LPCWSTR先转换成GB18030编码的多字节字符串,再把多字节的每个字节赋值给wchar_t数组的元素,代码示例如下:
std::string ChineseCharacter(LPCWSTR Data) { CString sHexValue; // 1. 把UTF-16的LPCWSTR转成GB18030多字节字符串 int gb18030Len = WideCharToMultiByte(CP_GB18030, 0, Data, -1, nullptr, 0, nullptr, nullptr); char* gb18030Buf = new char[gb18030Len]; WideCharToMultiByte(CP_GB18030, 0, Data, -1, gb18030Buf, gb18030Len, nullptr, nullptr); // 2. 把GB18030的每个字节转成wchar_t元素 wchar_t* targetStr = new wchar_t[gb18030Len]; // 包含终止符 for (int i = 0; i < gb18030Len; i++) { targetStr[i] = static_cast<wchar_t>(static_cast<unsigned char>(gb18030Buf[i])); sHexValue.Format("%02x", targetStr[i]); // 这里可以根据需要处理sHexValue的拼接逻辑 } // 3. 记得释放内存 delete[] gb18030Buf; // 使用完targetStr后也要delete[] targetStr; return sHexValue.GetString(); }
关键说明
WideCharToMultiByte(CP_GB18030, ...)是核心函数,负责把UTF-16宽字符转成GB18030多字节编码- 转换时要注意内存分配和释放,避免内存泄漏
- 如果你用的是MFC/ATL,也可以用
CStringA的转换简化操作:CStringA gb18030Str(Data, CP_GB18030);,再遍历gb18030Str的每个字节转成wchar_t
补充背景
GB18030是中国国家标准字符集编码,兼容所有Unicode字符,其中汉字"丂"的GB18030编码为两个字节:0x81 0x40,这就是你要的目标数值。
内容的提问来源于stack exchange,提问作者Ferrus
相关产品推荐
相关产品推荐

