字符串乱码问题


项目场景

项目开发中,程序 A 使用的是 Unicode 编码,程序 B 使用 UTF8 编码。A 与 B 进行网络通信,当 B 发送数据给 A,若数据中含有中文,则 A 收到的数据是乱码的。这时 A 需要将接收到的 UTF8 编码的数据转成 Unicode,同理,当 A 发送数据给 B 时,要将 Unicode 编码的数据转成 UTF8 再发送。

解决方法

来看一个例子:

// A 程序代码
#include <comutil.h>  
#pragma comment(lib, "comsuppw.lib")

// wstring转string
std::string WstringToString(const wstring& ws) {
    _bstr_t t = ws.c_str();
    char* pchar = (char*)t;
    string result = pchar;
    return result;
}
// UTF8转Unicode
std::wstring UTF8ToUnicode(const std::string & s) {
    std::wstring result;
    int n = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0);
    wchar_t * buffer = new wchar_t[n];
    ::MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, n);
    result = buffer;
    delete[] buffer;
    return result;
}

int main() {
    unsigned char ucDevName[64]; 
    // ...省略部分代码
    // ucDevName[]数组中放有从 B 接收来的数据,调试看起来是乱码的
    // 下面进行转换
    std::string strDevName(reinterpret_cast<char*>(ucDevName));
    std::wstring wstrDevName = UTF8ToUnicode(strDevName);
    strDevName = WstringToString(wstrDevName);
    memcpy(ucDevName, strDevName.c_str(), 64);  // 这时ucDevName[]数组中数据已经正常了
    return 0;
}

其他转换函数

除了上面例子的两个转换函数,下面再提供几个转换相关的函数:

void charToWchar(const char* ch, std::wstring& w_str) {
    wchar_t* wchar;
    int len = MultiByteToWideChar(CP_ACP, 0, ch, strlen(ch), NULL, 0);
    wchar = new wchar_t[len + 1];
    MultiByteToWideChar(CP_ACP, 0, ch, strlen(ch), wchar, len);
    wchar[len] = '\0';
    w_str = wchar;
    delete[] wchar;
}

void wcharToString(std::string& szDst, wchar_t *wchar) {
    wchar_t * wText = wchar;
    DWORD dwNum = WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, NULL, 0, NULL, FALSE);  // WideCharToMultiByte的运用
    char *psText;  // psText为char*的临时数组,作为赋值给std::string的中间变量
    psText = new char[dwNum];
    WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, psText, dwNum, NULL, FALSE);  // WideCharToMultiByte的再次运用
    szDst = psText;  // std::string赋值
    delete[]psText;  // psText的清除
}

// wstring版本的unicode转UTF8
std::string unicodeToUTF8_wstring(LPCWSTR lpszWideStr) {
    int nLen = WideCharToMultiByte(CP_UTF8, 0, lpszWideStr, -1, nullptr, 0, nullptr, nullptr);
    char *buffer = new char[nLen + 1];
    ZeroMemory(buffer, nLen + 1);
    WideCharToMultiByte(CP_UTF8, 0, lpszWideStr, -1, buffer, nLen, nullptr, nullptr);
    string multStr = buffer;
    delete[] buffer;
    return multStr;
}

// string版本的unicode转UTF8
std::string unicodeToUTF8_string(const std::string &strSrc) {
    int nwLen = ::MultiByteToWideChar(CP_ACP, 0, strSrc.c_str(), -1, NULL, 0);
    wchar_t * pwBuf = new wchar_t[nwLen + 1];  // 一定要加1,不然会出现尾巴
    ZeroMemory(pwBuf, nwLen * 2 + 2);
    ::MultiByteToWideChar(CP_ACP, 0, strSrc.c_str(), strSrc.length(), pwBuf, nwLen);
    int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
    char * pBuf = new char[nLen + 1];
    ZeroMemory(pBuf, nLen + 1);
    ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
    std::string retStr(pBuf);
    delete[]pwBuf;
    delete[]pBuf;
    pwBuf = NULL;
    pBuf = NULL;
    return retStr;
}

// string转wstring
wstring String2Wstring(const string& s) {
    _bstr_t t = s.c_str();  
    wchar_t* pwchar = (wchar_t*)t;  
    wstring result = pwchar;  
    return result; 
}

### 解决CString类型字符串乱码问题 在处理 `CString` 类型字符串时,如果遇到乱码问题,通常是因为字符编码设置不当引起的。MFC 支持多字节字符集(MBCS)和 Unicode 编程模式,在不同环境下需要采取不同的措施来确保正确处理字符编码。 #### 1. 设置项目属性为Unicode 为了使程序能够支持多种语言并避免乱码现象,建议将项目的字符集配置更改为 **Use Unicode Character Set**[^1]。这可以通过修改Visual Studio 中的项目属性实现: - 右键点击解决方案资源管理器中的项目名称; - 选择 "Properties"; - 导航到 Configuration Properties -> General; - 将 Character Set 更改为 Use Unicode Character Set. 这样做之后,所有的字符串都将默认使用宽字符 (`wchar_t`) 进行存储与操作,从而更好地适应国际化需求。 #### 2. 正确换不同类型之间的字符串 当涉及到 `std::string`, `LPCWSTR`, 或者其他类型的字符串相互之间化时,应该注意它们所使用的字符宽度差异。对于从窄字符(`char*`)向宽字符(`wchar_t*`) 的换可以利用 `_mbstowcs_s()` 函数;反之则可采用 `_wcstombs_s()`. 同样地,在 MFC 应用中也可以通过 `CT2W` 和 `CW2A` 宏来进行类似的换工作[^4]. ```cpp // Example of converting between std::string and CString under Unicode setting. #include <afx.h> // For CString class definition #include <atlconv.h> // For conversion macros like CT2CA, CW2A etc. void ConvertBetweenStdStringAndCString() { // From std::string to CString (assuming project uses Unicode character set) std::string narrowStr = "Hello World!"; CString wideStr; #ifdef _UNICODE CA2W converter(narrowStr.c_str()); wideStr = converter.m_psz; #else wideStr = narrowStr.c_str(); #endif // Display converted string using MessageBox function provided by Windows API ::MessageBox(NULL, static_cast<LPCTSTR>(wideStr), L"Converted String", MB_OK); } ``` #### 3. 处理文件读写过程中的编码问题 当从外部源加载数据或将内部表示保存至磁盘时,同样需要注意编码的一致性。例如,在打开文本文件之前指定正确的编码方式可以帮助防止因误判而产生的乱码情况。可以借助于 C++ 文件流类库提供的成员函数如 imbue 来设定特定区域环境下的 locale 对象: ```cpp #include <fstream> #include <locale> void ReadFileWithProperEncoding(const char* filePath) { std::ifstream fileStream(filePath); if (!fileStream.is_open()) return; try { // Specify UTF8 encoding when reading files on platforms where it's not default fileStream.imbue(std::locale(fileStream.getloc(), new std::codecvt_utf8<wchar_t>)); wchar_t buffer[256]; while (fileStream.good()) { fileStream.readsome(reinterpret_cast<char*>(buffer), sizeof(buffer)/sizeof(wchar_t)-1); wcout << buffer; } } catch (...) {} fileStream.close(); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值