utf-8 utf-16对比windows系统下wchar_t和char中文字符的二进制对比

博客对比了在Windows和Linux系统下,wchar_t、char以及UTF-8和UTF-16编码的中文字符的二进制表示。在Windows的VS2013中,wchar_t和UTF-16编码相同,而char使用GBK编码。在Linux环境下,wchar_t、char16_t和char的中文字符编码相同,均为UTF-16。讨论了UTF-8、UTF-16和GBK编码的优缺点,UTF-8适合网络传输,UTF-16在Windows下操作方便,而GBK编码在特定排序场景下可能更优。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对比的源程序(cpp) :


// 针对汉字的utf-8 和utf-16对比

#include "stdafx.h"
#include "windows.h"
#include <cstdint>
#include <iostream>
#include <bitset>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
    char *pc = "中国";
    cout << pc[0] << pc[1] << endl;// 中
    wchar_t* lpString = L"hi中国";
    wcout.imbue(locale("chs"));
    wcout << lpString[3] << endl; // 国
    cout << "------------wchar_t to utf-8----------------" << endl;
    char uf8[10] = { 0 };
    int nLenOfUf8, nReturnlen;
    nLenOfUf8 = WideCharToMultiByte(CP_UTF8, 0, lpString, -1, NULL, 0, NULL, NULL);
    //Header: Declared in Winnls.h; include Windows.h.  
    if (!nLenOfUf8)
        return false;
    nReturnlen = WideCharToMultiByte(CP_UTF8, 0, lpString, -1, uf8, nLenOfUf8, NULL, NULL);
    if (!nReturnlen)
    {
        return false;
    }
    setlocale(LC_ALL, "");
    cout << uf8[0] << uf8[1] << endl; // hi
    cout << uf8 << " :" << strlen(uf8) << endl; // hi乱码   8

    bitset<16> b(lpString[2]);
    cout << "wchar_t:  " << b << endl;// wchar_t (对后面的utf8就知道wchar_t就是utf-16)
    bitset<8> b1(uf8[2]);//1110 XXXX // 高4位
    bitset<8> b2(uf8[3]);//10XX XXXX // 中间6位
    bitset<8> b3(uf8[4]);//10XX XXXX // 低6位
    cout << "utf8: " << b1 << ' ' << b2 << ' ' << b3 << endl;
    cout << "---------wchar_t is utf16----utf8 to utf16-------------------" << endl;
    wchar_t ch[10] = { 0 };
    bitset<16> b4(((uf8[2] & 0x0f) << 12)//根据规则计算,把'中' '国'由utf8转成utf16
        + ((uf8[3] & 0x3f) << 6) + (uf8[4] & 0x3f) );
    cout << "utf-16: " << b4 << endl; // 中
    ch[0] = ((uf8[2] & 0x0f) << 12) + ((uf8[3] & 0x3f) << 6) + (uf8[4] & 0x3f);// 中
    ch[1] = ((uf8[5] & 0x0f) << 12) + ((uf8[6] & 0x3f) << 6) + (uf8[7] & 0x3f);// 国
    wcout << ch << endl;// 中国
    cout << "--------char-----------------" << endl;
    bitset<8> b5(pc[0]);
    bitset<8> b6(pc[1]);
    cout << "char : " << b5 << ' ' << b6 << endl;// 中    GBK编码的 '中' 的十六进制 D6D0
    return 0;
}

输出结果:


从这里可以看出。在vs2013 中 wchar_t 和utf_16,二进制位一样,占两字节。但是char,英文字母一个字节,汉字两个字节。存储同样汉字和前两者二进制位不一样,不是utf-16, 是GBK编码(在gbk 编码表里面查找验证过)。


linux  fedora23  下的测试源码如下:

#include <iostream>
#include <cwchar>
#include <bitset>
#include <cstdio>
#include <uchar.h>
#include <clocale>
using namespace std;
int main()
{
    printf("%s\n",setlocale(LC_ALL,NULL));
    setlocale(LC_ALL,"");
    printf("%s\n",setlocale(LC_ALL,NULL));
    char c[]="中国h";
    char16_t c16=u'中';
    char32_t c32=U'中';
    wchar_t wc[]=L"中国h";
    cout << "char  len: " << sizeof(c) << endl;
    cout << "char16len: " << sizeof(c16) << endl;
    cout << "wchar len: " << sizeof(wc) << endl;
    bitset<8> b0(c[0]);
    bitset<8> b1(c[1]);
    bitset<8> b2(c[2]);
    cout << "char 中: " << b0<<' '<< b1<<' '<< b2<< endl;
    bitset<16> b16(c16);
    cout << "char16中:" << b16 << endl;
    bitset<32> b32(c32);
    cout << "char32中:" << b32 << endl;
    bitset<32> b3(wc[0]);
    cout << "wchar中 :" << b3 << endl;
    bitset<8> b4(c[6]);
    cout << "char  h:" << b4 << endl;
    bitset<32> b5(wc[2]);
    cout << "wchar h:" << b5 <<endl;
    wprintf(L"%ls \n", L"wpr Wide char:");
    wcout << L"wcout Wide char" <<endl;
    locale loc("zh_CN.UTF-8");
    wcout.imbue(loc);
    wcout << wc[0] << endl;// 想输出中,失败
    return 0;
}

输出结果是:


在linux环境下,char 是utf-8,英文一个字节,汉字三个字节。.wchar_t 和 utf-32一样,占四字节。但是尝试输出wchar_t的汉字一直没输出来。


mingw下进行同样的测试 源代码如下:

#include <iostream>
#include <cstring>
#include <cwchar>
#include <clocale>
#include <bitset>
using namespace std;
int main(){
    setlocale(LC_ALL,"zh_CN.UTF-8");
    char a[] = u8"hi中国";//貌似不是utf-8
    char a2[] = "hi中国";
    wchar_t a3[] = { '中', '国' };
    cout << "char u8: " << strlen(a) << ' ' << sizeof(a) <<endl;
    cout << "char   : " << strlen(a2) << ' ' << sizeof(a2) << endl;
    cout << "wchar_t: " /*<< strlen(a3)*/ << ' ' << sizeof(a3) << endl;
    bitset<8> c0(a2[2]);
    bitset<8> c1(a2[3]);
    cout <<"char  : " << c0 << ' ' << c1 << endl;
    bitset<8> b0(a[2]);
    bitset<8> b1(a[3]);
    cout <<"u8    : " << b0 << ' ' << b1 << endl;
    bitset<16> b2(a3[0]);
    bitset<16> b3(a3[1]);
    cout <<"whar_t: "<< b2 << ' ' << b3 << endl;
    char16_t u16 = '中';
    cout << "u16 : " << sizeof(u16) << endl;
    bitset<16> b4(u16);
    cout << "u16 : " << b4 << ' ' << sizeof(L'h') << endl;
    cout << "----------mingw--u/L貌似只识别英文------------" << endl;
    bitset<16> b5(u'h');
    bitset<16> b6(L'h');
    cout << "u16:  " << b5 << endl;
    cout << "wchar:" << b6 << endl;
    return 0;
}

输出结果如下:


对于同样的汉字,wchar_t ,char16_t 以及char里面存的二进制都一样,且都同等于vs下的char中汉字(gbk编码)。

编译的时候有警告,也不知道是否因为此原因这三者才一样的,没找到如何消除警告的方法。


中文字符编码之GBK,UTF-16和UTF-8

(gbk, utf8 ,utf16 编程中经常会遇到这三种字符编码形式的相互转换问题,以至于许多第三方的库不明原因的调用失败)。


下面是转载一段话,总结的比较好

简单几句话总结Unicode,UTF-8和UTF-16

概念

先说一说基本的概念,这包括什么是Unicode,什么是UTF-8,什么是UTF-16。

Unicode,UTF-8,UTF-16完整的说明请参考Wiki(UnicodeUTF-8UTF-16)。用比较简单的话来说就是,Unicode定义了所有可以用来表示字符的数值集合(称之为Code Point)。UTF-8和UTF-16等UTF标准定义了这些数值和字符的映射关系。

UTF-8

优势

UTF-8最大的优势是,没有字节序的概念。所以特别适合用于字符串的网络数据传输,不用考虑大小端问题。

劣势

本地字符串处理过程中,如果使用UTF-8,对于英文字符的处理没有太大的问题。一个char变量表示一个英文字符。但是对于中文等远东字符集来说,就比较坑爹了。char str[]; str[0]并不能完整表示一个汉字。UTF-8编码格式下,一个汉字需要至少3个char才能表示。这对于通过下标来操作字符串的操作来说是非常痛苦的一件事情。

另外,一个汉字需要至少3个char来表示,也让汉字在网络传输上存在劣势,占用太多流量。

UTF-16

优势

UTF-16 LE是windows上默认的Unicode编码方式,使用wchar_t表示。所有wchar_t *类型的字符串(包括硬编码在.h/.cpp里的字符串字面值),VC都自动采用UTF-16的编码(字符串字面值,literal string,存在很多坑。特别是char *类型的字面值,最终内存使用何种编码方式完全取决于当前文件的编码方式。也就是说当前文件如果是GBK编码的,那么文件里char * str = "中午",str指向的内存字符串二进制是使用GBK编码的。如果文件编码是UTF-8,那么内存是使用UTF-8编码。所以为什么一直要强调字符串应该放在资源文件里,而不是硬编码在.h/.cpp文件里!)。

UTF-16另外一个优势就是常用字符都可以使用两个个字节表示,也就是一个wchar_t(这里指Windows平台)。所以,在Windows平台上,特别适合使用wchar_t来作为字符串的存储基类型。一个wchar_t表示一个字符。操作使用非常方便。

劣势

没有统一的表示UTF-16编码的字符类型。C++98/03里对wchar_t的定义是非常宽泛的。这导致在Windows平台上,wchar_t是2字节的;在Unix-like系统上是4字节的。代码移植上,可能会遇到挑战(我没移植过,所以不确定会有什么难度,以及难度有多大)。

即使最新的C++11里已经定义除了char16_t表示UTF-16,MS的VS2013还不支持char16_t。所以目前使用char16_t还不具移植性。

据我了解,UTF-16编码和GBK编码相比,还存在一个排序的劣势。也就是说,如果要按照汉语拼音的字母顺序对汉字进行排序,GBK会得到正确的结果,而UTF-16就不行(暂时我还没这种需求,所以我没验证过,不过好像我马上就要与到这种需求了,到时候我再验证下)。

UTF-16编码字符串的网络传输,要考虑大小端的问题。

UTF-32

优势

这个优势就明显了,所有字符都是4字节,fix-length。一个wchar_t(Unix-like系统上)表示一个字符。

劣势

对于以英文为主的字符串来说,空间消耗大。

面临和上面UTF-16一样的问题。一致性,排序,网络传输。char32_t VS2013还不支持(甚至VS 14 CPT也没打算支持)。

总结

UTF-8最适合用来作为字符串网络传输的编码格式。UTF-16最适合当作本地字符串编码格式。如果定义好了网络传输协议,那么UTF-16也非常合适当作网络字符串传输的编码格式,特别是中文等远东地区字符集。比起UTF-8来说,节省流量。UTF-32没什么特殊癖好或者需求的话,暂时还用不上。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值