美文网首页
c++ vc编码踩坑总结

c++ vc编码踩坑总结

作者: YuWenHaiBo | 来源:发表于2019-07-26 16:41 被阅读0次

    预备知识

    参考这两个连接
    从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
    
    
    

    相关文章

      网友评论

          本文标题:c++ vc编码踩坑总结

          本文链接:https://www.haomeiwen.com/subject/xfrdrctx.html