c++ vc编码踩坑总结

2019-07-26  本文已影响0人  YuWenHaiBo

预备知识

参考这两个连接
从Emoji的限制到Unicode编码
带你玩转Visual Studio——带你理解多字节编码与Unicode码

vs studio c++ 项目目前只有两种编码格式,多字节和Unicode,默认都是多字节,这个有好处就是char兼容ascii 编码,缺点是当我们赋值其他国家语言时候就不能直接赋值了比如

// 多字节编码
void TestChar()
{
    char ch1 = 's';             // 正确
    cout << "ch1:" << ch1 << endl;
    char ch2 = '中';             // 错误,一个char不能完整存放一个汉字信息
    cout << "ch2:" << ch2 << endl;

    char str[4] = "中";          //前三个字节存放汉字'中',最后一个字节存放字符串结束符\0
    cout << "str:" << str << endl;
    //char str2[2] = "国";       // 错误:'str2' : array bounds overflow
    //cout << str2 << endl;
}

//  Unicode 编码
void TestWchar_t()
{
    wcout.imbue(locale("chs"));     // 将wcout的本地化语言设置为中文

    wchar_t wch1 = L's';            // 正确
    wcout << "wch1:" << wch1 << endl;
    wchar_t wch2 = L'中';            // 正确,一个汉字用一个wchar_t表示
    wcout << "wch2:" << wch2 << endl;
    
    wchar_t wstr[2] = L"中";         // 前两个字节(前一个wchar_t)存放汉字'中',最后两个字节(后一个wchar_t)存放字符串结束符\0
    wcout << "wstr:" << wstr << endl;
    wchar_t wstr2[3] = L"中国";
    wcout << "wstr2:" << wstr2 << endl;
}

多字节 处理编码

一般的项目选择多字节后,默认编码(我的是简体中文的vs studio 2013)是gb2312,可以从高级保存里面看到当前的文件的编码格式。


编码

这个时候我们可以调出我们的内存查看器查看我们的中国的编码是
d6 d0 b9 fa

GB2312

我们可以在这个网址在线编码看到如下结果



中国
Unicode 编码是 :
0x4E2D 0x56FD
utf8 编码是
e4 b8 ad e5 9b bd

我们可以根据这个函数来转为utf8 ,一般本地字符串这个不会导致乱码

string GBKToUTF8(const char* strGBK)
{
    int len = MultiByteToWideChar(CP_ACP, 0, strGBK, -1, NULL, 0);
    wchar_t* wstr = new wchar_t[len + 1];
    memset(wstr, 0, len + 1);
    MultiByteToWideChar(CP_ACP, 0, strGBK, -1, wstr, len);
    len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
    char* str = new char[len + 1];
    memset(str, 0, len + 1);
    WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
    string strTemp = str;
    if (wstr) delete[] wstr;
    if (str) delete[] str;
    return strTemp;
}

但是通常我们会从数据库取数据,这个坑就比较多了,我用的是ado 来从sql server 获取nvarchar 的数据获取的结果如下:


可以看到我们获取的数据是Unicode的编码格式的,所以我们要直接转成utf8就行了不需要转成Unicode了。
这里有必要说下,ado 操作数据库有遍历结果集传入参数获取值,我目前发现使用结果集获取的是Unicode 编码,传入参数之前项目碰到过乱码了,所以建议使用结果集。

tips

这里怎么调出内存查看器和高级保存选项,大家可以自己搜索下,自己动手多学习学习下,我就不写入里面了。

附录:

Unicode 转utf8 的函数

bool Unicode2UTF(vector<char> &Dest, wchar_t *szSrc)
{
    int iTextLen = wcslen(szSrc);
    if (iTextLen == 0)
    {
        return false;
    }
    iTextLen = WideCharToMultiByte(CP_UTF8,
        0,
        (LPWSTR)szSrc,
        -1,
        NULL,
        0,
        NULL,
        NULL);
    if (iTextLen == 0)
        return false;
    Dest.resize(iTextLen);
    ::WideCharToMultiByte(CP_UTF8,
        0,
        (LPWSTR)szSrc,
        -1,
        &*Dest.begin(),
        iTextLen,
        NULL,
        NULL);

    return true;

}


Windows API函数MultiByteToWideChar用于多字节编码字符串向宽字符串(即UTF-16 LE)的转码。它的第一个参数的常用值是CP_ACP和CP_OEMCP。
CP_ACP和CP_OEMCP,分别是指当前计算机上的Windows操作系统的Windows代码页与OEM代码页。对于东亚的简体中文、繁体中文、日文、韩文等Win操作系统语言环境,这两种代码页是同一个,如简体中文是代码页936即GB2312字符集,繁体中文是950即大五码字符集,韩文是949、日文是932。对于西方国家的拼音文字语言设置,两个代码页不同。典型的如English_US,其Windows代码页是1252、OEM代码页是437,还有第三个代码页ISO-8859-1又称Latin-1或“西欧语言”,是针对英语法语西语德语等西欧语言的扩展ASCII字符集。这三者(1252、437、8859-1)都是针对英语但并不相同。

编码转换规则
Unicode转UFT-8:设置WideCharToMultiByte的CodePage参数为CP_UTF8
Unicode转ANSI:设置WideCharToMultiByte的CodePage参数为CP_ACP
UTF-8转Unicode:设置MultiByteToWideChar的CodePage参数为CP_UTF8
ANSI转Unicode:设置MultiByteToWideChar的CodePage参数为CP_ACP
UTF-8转ANSI:先将UTF-8转换为Unicode,再将Unicode转换成ANSI 
ANSI转UTF-8:先将ANSI转换为Unciode,再将Unicode转换成ANSI。

ANSI 这里并不是严格的,是ANSI的拓展,指的是本地的编码,如中文就是GB2312


上一篇下一篇

猜你喜欢

热点阅读