字符编码、字符存储、字符转换及工程中字符的使用
2016-05-16 15:09
281 查看
字符编码、字符存储、字符转换及工程中字符的使用
版本控制
一、 前言
1. 目的
本文主要用于整理字符相关知识,包括字符编码、字符存储、行业标准、文件读写、工程注意事项等涉及字符相关的内容,
从而在实际工程中更好地设计和使用字符、更快地解决字符问题。
2. 适用范围
本文标题是“Windows C++字符编码、存储、转换大全”,
但“第三段.行业标准“属于概念总结,不涉及具体的编程语言和平台,是通用的知识,读者无需编程基础,但需要一定的计算机基础。
第四段到第七段仅适用于Windows C++ VC环境,需要读者具备一定的C++开发基础。
3. 开发环境及辅助工具
操作系统: Windows7 64bit中文版
IDE: VS2008+Sp1
WinHex, 下载地址http://www.winhex.com/winhex/index-m.html
Notepad++:下载地址https://notepad-plus-plus.org/
4. 声明
本文由施小丰发表于http://www.smallgui.com/,任何人以任何形式转载时,请确保本文完整,包括本节权利声明。
二、 常见问题
在使用Windows、C++、VC编程时,经常遇到以下个问题
1. 函数调用时参数字符编码不匹配
比如提示cannot convertparameter 3 from 'LPCWSTR' to 'const char *'
2. 存储或解析字符后是乱码
比如程序存储数据至文本文件后,使用Notepad打开发现是乱码。
3. 网络请求时由于字符问题导致乱码
比如发送http请求时,由于编码格式不对,对方服务器无法正确解析数据导致没有服务器正确执行预期操作
三、 字符理论
面对字符编码,我们不禁要问,怎么会产生字符编码问题,为什么不能统一字符编码?那就得先看下字符编码的历史了。
1. 标准ASCII码
计算机内的信息本质上都是二进制信息,即只有0和1两种状态,则此时字符本身,比如'A'需要用多个二进制位表示。
所以为统一各种字符的二进制值,美国国家标准委员会(American National Standard Institute,ANSI)于上个世纪60年代制定了叫做ASCII码(AmericanStandard Code for Information Interchange,美国标准信息交换码。)的字符编码。
标准ASCII码表使用8个二进制,最高位统一为0,所以实际使用7个低二进制位,从而规定了128个字符(2的7次方)的编码,见本文附件1.ASCII码表。
(这里其实来到了计算机行业一个恒久不变的坑:“够了”,比如这里的ASCII码表,比如当时的IP地址,比如比尔盖茨先生的“640K ought to be enough for anyone”,比如千年虫问题。。。)
2. 非标准ASCII码
纯英文使用ASCII码或许够了,但到非英语国家时,显然128个字符不够用,于是很多国家都充分利用起最高位来引入新的符号,
但每个国家对于扩展位并没有统一,于是出现”130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。”。
到目前为止ASCII已经不够用了,必须设计新的编码方式,但新编码方式至少需要解决六个问题
(1)0-127各国都一样,都是标准ASCII码,新编码方式需要兼容
(2)如何统一现有的所有字符
(3)如何在兼容原有字符的基础上,能在未来扩展新字符
(4)新编码是否能够不显著增加小子集字符国家的复杂度,比如对纯英语国家,128种字符够用,完全用全新的多个字节的编码方式,太浪费了。
(5)如何知道一个文件的编码格式和存储方式(大端小端),从而使用正确解析文件内容
(6)如何确保在网络传输过程中双方的编码和解码一致
3. Unicode、UCS2、UCS4
为了解决上述六个问题,有两个国际组织试图设计Unicode,分别是ISO(国际标准化组织)和Unicode.org(软件制造商协会),ISO开发ISO 10646项目,Unicode开发Unicode项目。
从1999年的Unicode3.0开始,Unicode项目和ISO10646项目的字库和字符已经一样,所以我们可以认为他们是一样的。
Unicode的目的是给符号进行编码(注意不是存储,也不是传输),目前常用的实现是UCS2,使用两个字节(16位)来表示一个字符,如汉字“施”的Unicode编码为\u65bd(可用在线工具http://tool.chinaz.com/tools/unicode.aspx转换)
,其中\u表示这是一个unicode编码(实际可忽略这个\u,仅仅为了区分而标记),其编码为十六进制的65bd。
了解了其形式,我们看看针对上面提出的六个问题,Unicode是如何解决的:
(1)标准ASCII码在Unicode编码中没变,比如字母A在ASCII中为0x41,在Unicode中的UCS2(实际上我们一般直接称UCS2为Unicode)实现中为\u0041,只是高位被用0填充了,所以第一个问题解决了
(2)Unicode为每个字符定义了一个唯一的编号,且字符对应的编码确定好以后,不再更改(至少低位不更改,高位可能由于后续扩展会统一填充),第二个问题也解决了
(3)ASCII码因为只有8个二进制位,所以不够用,而Unicode标准本身并没有规定具体多少个字节,
但真正实现Unicode则必须考虑这个问题,现在实际用的最多的是用两个字节(即16位,共有65536钟表示)表示一个符号,这种实现方式称做UCS2。UCS2实际上是Unicode的一个子集,
也有用四个字节表示一个字符的称作UCS4,所以未来如果忽然增加了很多新字符,则可以设计UCS8、UCS16等实现,且低位兼容UCS2和UCS4即可,第三个问题也解决了
(4)(5)(6)三个问题涉及到编码的具体存储和协商方式,详见第四小节4.UTF8、UTF16, 第五小节5.大端小端, 第六小节6.codepage和charset
4. UTF8、UTF16
UTF8或者UTF16的出现,本质上是解决上面6个问题中的第4个,即如果所有的字符都用相同字节的编码来表示,那么对于小字符集国家而言,这个存储太浪费空间了(可能当年的存储成本很高导致)。
这里以UTF-8为例,UTF-8是对Unicode编码格式(一般平时所说的Unicode等同于UCS2)的一种存储实现。UTF-8和UCS2的转换关系如下所示
UCS2编码(16进制) UTF8字节流(二进制) 备注
0000-007F 0xxxxxxx 其实就是标准ASCII码
0080-07FF 110xxxxx 10xxxxxx
0800-FFFF 1110xxxx 10xxxxxx 10xxxxxx
以汉字“施”为例,其unicode编码为65bd,也即Unicode二进制代码为
110010110111101
则转换成UTF8编码时,使用上述二进制代码从右往左依次填充1110xxxx 10xxxxxx 10xxxxxx中的x,左边不足部分使用0填充,得到其UTF8编码二进制值为
11100110 10010110 10111101
转换成16进制,即为E6 96 BD,我们在记事本中写入施,然后另存为UTF8,格式,再使用WinHex观察,前三个字节EF BB BF属于BOM,后面三个字节就是汉字“施”的UTF8编码,好了,新的问题又出现了,BOM是什么?
5. 大端、小端、BOM、零宽度非换行空格
汉字“施”的Unicode编码(再次提醒,其实一般所说的Unicode编码就是指UCS2编码)是65bd,占用两个字节,
于是就存在两种存储方式,
大端:65在高位的存储方式就是大端
小端:65在低位的存储方式叫做小端
为了区分当前存储或传输方式到底是大端还是小端,Unicode
BOM:字节顺序标记,FF FE
零宽度非换行空格:我们可以理解成BOM的一个组成部分
通过在windows中的Notepad++中写入字符保存为不同的格式,然后用WinHex打开可以得到不同编码的字节顺序标记(本表仅在Windows平台下测试过)
上节中提到的我们存储的汉字“施”就是使用UTF8编码,其中前面三个字节就是BOM。
但是这个BOM其实是Windows的“特产”,所以存储UTF8时,最好不要带BOM。网上这篇文章/article/4774579.html对于UTF8应不应该带BOM讲的比较清楚。结论是UTF-8尽量不要带BOM。
那么新问题又来了,假如我们在文件中只是存储字符的UTF8码,而没有BOM信息的话,我们在解析文件时,如何确定编码方式,尤其在网络上传输信息,比如html的时候,浏览器如何确定编码方式?
6. 文件编码和charset
(1)文件编码
第一种情况是纯文本文件,且没有BOM信息,这种情况下从纯软件的角度来讲其实只能猜测尝试编码方式;可以按照http://blog.csdn.net/turingo/article/details/8136644这篇博文实现。
第二种情况是纯文本文件,有BOM信息,这种情况下从通过BOM信息判断文件的编码格式。
第三种情况是文件本身已经描述了其编码方式,比如标准xml在声明中需要表明其本身的编码方式,一般形式如下:<?xml version="1.0" encoding="utf-8"?>,其中encoding表明文件本身是用utf-8编码的。
(2)网络传输
第一种情况是自定义的socket的话,需要双方自己协商确定编码格式。
另外一种是标准协议或语言,比如html。Html标记语言有一个属性charset,这个属性在html中一般是head节点的第一个子节点,这样浏览器解析html时,会先用默认的编码格式读取一部分html数据(比如GB2312),如果读取到当前html的charset后,与当前默认的编码格式不同,则浏览器使用charset中指定的编码重新读取html并显示。下面我们来验证一下。
使用Chrome浏览器打开百度首页后,右击查看网页源代码后获取的百度首页的html内容,
我们右击另存到本地计算机上后,使用Notepad++打开该文件,然后再使用Chrome打开,字符显示正常(样式会由于css样式表确实导致走样)
然后将其中的utf-8修改为GB2312
再刷新刚打开的页面,发现字符显示已经是乱码
所以对于网页或者传输而言,你要知道你传输的字符或者文件的编码格式,然后由你自己告诉对方你的编码格式,如果你告诉别人的编码方式和实际文件的编码格式不一致,那么结果很可能是两个字:乱码。
四、 常用字符编码标准
五、 字符定义总结
在C++体系中,字符类型本质上只有char和wchar_t两种,其他的要么只是封装,比如string封装了char数组,wstring封装了wchar_t数组,要么是为了兼容不同的语言或组件,比如CString是MFC框架下的字符串,_bstr_t是COM组件中的字符串。下表列出了常用的字符类型。
其它类型见WinNT.h头文件:
typedef WCHAR *PWCHAR,*LPWCH, *PWCH;
typedef CONST WCHAR *LPCWCH, *PCWCH;
typedef _Null_terminated_WCHAR *NWPSTR, *LPWSTR, *PWSTR;
typedef _Null_terminated_ PWSTR *PZPWSTR;
typedef _Null_terminated_ CONST PWSTR *PCZPWSTR;
typedef _Null_terminated_ WCHAR UNALIGNED *LPUWSTR, *PUWSTR;
typedef _Null_terminated_ CONST WCHAR *LPCWSTR, *PCWSTR;
typedef _Null_terminated_ PCWSTR *PZPCWSTR;
typedef _Null_terminated_ CONST PCWSTR *PCZPCWSTR;
typedef _Null_terminated_ CONST WCHAR UNALIGNED *LPCUWSTR, *PCUWSTR;
typedef _NullNull_terminated_WCHAR *PZZWSTR;
typedef _NullNull_terminated_ CONST WCHAR *PCZZWSTR;
typedef _NullNull_terminated_ WCHAR UNALIGNED *PUZZWSTR;
typedef _NullNull_terminated_ CONST WCHAR UNALIGNED *PCUZZWSTR;
typedef WCHAR *PNZWCH;
typedef CONST WCHAR *PCNZWCH;
typedef WCHAR UNALIGNED *PUNZWCH;
typedef CONST WCHAR UNALIGNED *PCUNZWCH;
typedef CONST WCHAR*LPCWCHAR, *PCWCHAR;
typedef CONST WCHAR UNALIGNED *LPCUWCHAR, *PCUWCHAR;
//
// UCS (Universal Character Set) types
//
typedef unsigned longUCSCHAR;
#ifndef _TCHAR_DEFINED
typedef WCHAR TCHAR, *PTCHAR;
typedef WCHAR TBYTE , *PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */
typedef LPWCH LPTCH, PTCH;
typedef LPCWCH LPCTCH, PCTCH;
typedef LPWSTR PTSTR, LPTSTR;
typedef LPCWSTR PCTSTR, LPCTSTR;
typedef LPUWSTR PUTSTR, LPUTSTR;
typedef LPCUWSTR PCUTSTR, LPCUTSTR;
typedef LPWSTR LP;
typedef PZZWSTR PZZTSTR;
typedef PCZZWSTR PCZZTSTR;
typedef PUZZWSTR PUZZTSTR;
typedef PCUZZWSTR PCUZZTSTR;
typedef PZPWSTR PZPTSTR;
typedef PNZWCH PNZTCH;
typedef PCNZWCH PCNZTCH;
typedef PUNZWCH PUNZTCH;
typedef PCUNZWCH PCUNZTCH;
#define __TEXT(quote) L##quote // r_winnt
看了这么多字符类型,只能说C\C++语言体系(不仅仅包括语言本身,还包括配套类库)的统一性还停留在上个实际的水平,对于这种奇奇怪怪的类型,遇到的时候去go to definition就够了。时间终将会逐渐淘汰这些历史过度的产物。
六、 字符函数总结
七、 工程总结
1.VS工程编码
VS2008
2.UTF8编码存储文件
3.xml
4. 文件读写
5.多语言
6.http
7.哈夫曼编码
八、 参考文献及博客
1. 百度百科:ASCII
http://baike.baidu.com/link?url=fpRp_IBr7z9azzwOUgwJM2cszeFGJxrS-KB_GB42i8ETkAwjkoR-JHEAHIRzdE7BZBCwqJd7QP7v9v25Xb7gJa
2. 维基百科:ISO/IEC646
https://wuu.wikipedia.org/wiki/ISO/IEC_646
3. 字符编码
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
4. Unicode组织
http://www.unicode.org/
5. The Absolute Minimum Every Software Developer Absolutely, PositivelyMust Know About Unicode and Character Sets (No Excuses!)
http://www.joelonsoftware.com/articles/Unicode.html
6. codePage和charset
/article/4661419.html
7. 程序员趣味读物:谈谈Unicode编码
/article/9296337.html
8. 字符编码(ucs2_+unicode_+utf8_+gb2312)
http://blog.sina.com.cn/s/blog_958a07d0010136y1.html
9. UTF-8编码规则
/article/4921541.html
10. Unicode转UTF8
/article/9932275.html
11. UTF8最好不要带BOM
/article/4774579.html
12. Unicode VS Multibyte
http://blog.codingnow.com/2006/03/unicode_vs_multibyte.html
13.
Unicode(UTF-8,UTF-16)令人混淆的概念
/article/6061801.html
14.
简单几句话总结Unicode,UTF-8和UTF-16
/article/7164511.html
15. How to: Convert BetweenVarious String Types
https://msdn.microsoft.com/en-US/library/ms235631
16. C++中的wchar_t
/article/6491263.html
17. C++官网
http://www.cplusplus.com/
18. BSTR类型跟_bstr_t区别
https://www.douban.com/note/188555222/
19.
搞清楚VC++中的char,wchar_t,TCHAR
/article/8786766.html
20.
关于char,wchar_t, TCHAR, _T(),L,宏 _T、TEXT,_TEXT、L
/article/6395232.html
21. CString与LPCWSTR、LPSTR、char*、LPWSTR等类型的转换
/article/3627260.html
22.
多字符集(ANSI)和UNICODE及字符串处理方式准则
/article/9005242.html
23.
BIG5编码, GB编码(GB2312, GBK,...), Unicode编码,
UTF8,WideChar, MultiByte, Char 说明与区别
/article/1563271.html
24.
GB2312, BIG5,UTF8, Unicode之间的互换
/article/1563444.html
25. ANSI、UNICODE、UTF-8、GB2312、GBK、DBCS、UCS的区别和由来
http://blog.chinaunix.net/uid-20743151-id-326455.html
九、 附录
1.ASCII码表
版本控制
版本 | 时间(北京时间) | 作者 | 备注 |
V1.0 | 2016-05-13 | 施小丰 | 创建本文、第七章工程总结尚未完成 |
1. 目的
本文主要用于整理字符相关知识,包括字符编码、字符存储、行业标准、文件读写、工程注意事项等涉及字符相关的内容,
从而在实际工程中更好地设计和使用字符、更快地解决字符问题。
2. 适用范围
本文标题是“Windows C++字符编码、存储、转换大全”,
但“第三段.行业标准“属于概念总结,不涉及具体的编程语言和平台,是通用的知识,读者无需编程基础,但需要一定的计算机基础。
第四段到第七段仅适用于Windows C++ VC环境,需要读者具备一定的C++开发基础。
3. 开发环境及辅助工具
操作系统: Windows7 64bit中文版
IDE: VS2008+Sp1
WinHex, 下载地址http://www.winhex.com/winhex/index-m.html
Notepad++:下载地址https://notepad-plus-plus.org/
4. 声明
本文由施小丰发表于http://www.smallgui.com/,任何人以任何形式转载时,请确保本文完整,包括本节权利声明。
二、 常见问题
在使用Windows、C++、VC编程时,经常遇到以下个问题
1. 函数调用时参数字符编码不匹配
比如提示cannot convertparameter 3 from 'LPCWSTR' to 'const char *'
2. 存储或解析字符后是乱码
比如程序存储数据至文本文件后,使用Notepad打开发现是乱码。
3. 网络请求时由于字符问题导致乱码
比如发送http请求时,由于编码格式不对,对方服务器无法正确解析数据导致没有服务器正确执行预期操作
三、 字符理论
面对字符编码,我们不禁要问,怎么会产生字符编码问题,为什么不能统一字符编码?那就得先看下字符编码的历史了。
1. 标准ASCII码
计算机内的信息本质上都是二进制信息,即只有0和1两种状态,则此时字符本身,比如'A'需要用多个二进制位表示。
所以为统一各种字符的二进制值,美国国家标准委员会(American National Standard Institute,ANSI)于上个世纪60年代制定了叫做ASCII码(AmericanStandard Code for Information Interchange,美国标准信息交换码。)的字符编码。
标准ASCII码表使用8个二进制,最高位统一为0,所以实际使用7个低二进制位,从而规定了128个字符(2的7次方)的编码,见本文附件1.ASCII码表。
(这里其实来到了计算机行业一个恒久不变的坑:“够了”,比如这里的ASCII码表,比如当时的IP地址,比如比尔盖茨先生的“640K ought to be enough for anyone”,比如千年虫问题。。。)
2. 非标准ASCII码
纯英文使用ASCII码或许够了,但到非英语国家时,显然128个字符不够用,于是很多国家都充分利用起最高位来引入新的符号,
但每个国家对于扩展位并没有统一,于是出现”130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。”。
到目前为止ASCII已经不够用了,必须设计新的编码方式,但新编码方式至少需要解决六个问题
(1)0-127各国都一样,都是标准ASCII码,新编码方式需要兼容
(2)如何统一现有的所有字符
(3)如何在兼容原有字符的基础上,能在未来扩展新字符
(4)新编码是否能够不显著增加小子集字符国家的复杂度,比如对纯英语国家,128种字符够用,完全用全新的多个字节的编码方式,太浪费了。
(5)如何知道一个文件的编码格式和存储方式(大端小端),从而使用正确解析文件内容
(6)如何确保在网络传输过程中双方的编码和解码一致
3. Unicode、UCS2、UCS4
为了解决上述六个问题,有两个国际组织试图设计Unicode,分别是ISO(国际标准化组织)和Unicode.org(软件制造商协会),ISO开发ISO 10646项目,Unicode开发Unicode项目。
从1999年的Unicode3.0开始,Unicode项目和ISO10646项目的字库和字符已经一样,所以我们可以认为他们是一样的。
Unicode的目的是给符号进行编码(注意不是存储,也不是传输),目前常用的实现是UCS2,使用两个字节(16位)来表示一个字符,如汉字“施”的Unicode编码为\u65bd(可用在线工具http://tool.chinaz.com/tools/unicode.aspx转换)
,其中\u表示这是一个unicode编码(实际可忽略这个\u,仅仅为了区分而标记),其编码为十六进制的65bd。
了解了其形式,我们看看针对上面提出的六个问题,Unicode是如何解决的:
(1)标准ASCII码在Unicode编码中没变,比如字母A在ASCII中为0x41,在Unicode中的UCS2(实际上我们一般直接称UCS2为Unicode)实现中为\u0041,只是高位被用0填充了,所以第一个问题解决了
(2)Unicode为每个字符定义了一个唯一的编号,且字符对应的编码确定好以后,不再更改(至少低位不更改,高位可能由于后续扩展会统一填充),第二个问题也解决了
(3)ASCII码因为只有8个二进制位,所以不够用,而Unicode标准本身并没有规定具体多少个字节,
但真正实现Unicode则必须考虑这个问题,现在实际用的最多的是用两个字节(即16位,共有65536钟表示)表示一个符号,这种实现方式称做UCS2。UCS2实际上是Unicode的一个子集,
也有用四个字节表示一个字符的称作UCS4,所以未来如果忽然增加了很多新字符,则可以设计UCS8、UCS16等实现,且低位兼容UCS2和UCS4即可,第三个问题也解决了
(4)(5)(6)三个问题涉及到编码的具体存储和协商方式,详见第四小节4.UTF8、UTF16, 第五小节5.大端小端, 第六小节6.codepage和charset
4. UTF8、UTF16
UTF8或者UTF16的出现,本质上是解决上面6个问题中的第4个,即如果所有的字符都用相同字节的编码来表示,那么对于小字符集国家而言,这个存储太浪费空间了(可能当年的存储成本很高导致)。
这里以UTF-8为例,UTF-8是对Unicode编码格式(一般平时所说的Unicode等同于UCS2)的一种存储实现。UTF-8和UCS2的转换关系如下所示
UCS2编码(16进制) UTF8字节流(二进制) 备注
0000-007F 0xxxxxxx 其实就是标准ASCII码
0080-07FF 110xxxxx 10xxxxxx
0800-FFFF 1110xxxx 10xxxxxx 10xxxxxx
以汉字“施”为例,其unicode编码为65bd,也即Unicode二进制代码为
110010110111101
则转换成UTF8编码时,使用上述二进制代码从右往左依次填充1110xxxx 10xxxxxx 10xxxxxx中的x,左边不足部分使用0填充,得到其UTF8编码二进制值为
11100110 10010110 10111101
转换成16进制,即为E6 96 BD,我们在记事本中写入施,然后另存为UTF8,格式,再使用WinHex观察,前三个字节EF BB BF属于BOM,后面三个字节就是汉字“施”的UTF8编码,好了,新的问题又出现了,BOM是什么?
5. 大端、小端、BOM、零宽度非换行空格
汉字“施”的Unicode编码(再次提醒,其实一般所说的Unicode编码就是指UCS2编码)是65bd,占用两个字节,
于是就存在两种存储方式,
大端:65在高位的存储方式就是大端
小端:65在低位的存储方式叫做小端
为了区分当前存储或传输方式到底是大端还是小端,Unicode
BOM:字节顺序标记,FF FE
零宽度非换行空格:我们可以理解成BOM的一个组成部分
通过在windows中的Notepad++中写入字符保存为不同的格式,然后用WinHex打开可以得到不同编码的字节顺序标记(本表仅在Windows平台下测试过)
编码 | BOM(十六进制) | 备注 |
ASCII | 无 | 相当于txt另存为ASCII |
UTF-8 | EF BB BF | 相当于txt另存为utf8 |
UTF-8无BOM | 无 | 相当于UTF-8去掉文件头BOM |
小端 | FF FE | 相当于txt另存为Unicode |
大端 | FE FF | 相当于txt另存为Unicode big endian |
但是这个BOM其实是Windows的“特产”,所以存储UTF8时,最好不要带BOM。网上这篇文章/article/4774579.html对于UTF8应不应该带BOM讲的比较清楚。结论是UTF-8尽量不要带BOM。
那么新问题又来了,假如我们在文件中只是存储字符的UTF8码,而没有BOM信息的话,我们在解析文件时,如何确定编码方式,尤其在网络上传输信息,比如html的时候,浏览器如何确定编码方式?
6. 文件编码和charset
(1)文件编码
第一种情况是纯文本文件,且没有BOM信息,这种情况下从纯软件的角度来讲其实只能猜测尝试编码方式;可以按照http://blog.csdn.net/turingo/article/details/8136644这篇博文实现。
第二种情况是纯文本文件,有BOM信息,这种情况下从通过BOM信息判断文件的编码格式。
第三种情况是文件本身已经描述了其编码方式,比如标准xml在声明中需要表明其本身的编码方式,一般形式如下:<?xml version="1.0" encoding="utf-8"?>,其中encoding表明文件本身是用utf-8编码的。
(2)网络传输
第一种情况是自定义的socket的话,需要双方自己协商确定编码格式。
另外一种是标准协议或语言,比如html。Html标记语言有一个属性charset,这个属性在html中一般是head节点的第一个子节点,这样浏览器解析html时,会先用默认的编码格式读取一部分html数据(比如GB2312),如果读取到当前html的charset后,与当前默认的编码格式不同,则浏览器使用charset中指定的编码重新读取html并显示。下面我们来验证一下。
使用Chrome浏览器打开百度首页后,右击查看网页源代码后获取的百度首页的html内容,
我们右击另存到本地计算机上后,使用Notepad++打开该文件,然后再使用Chrome打开,字符显示正常(样式会由于css样式表确实导致走样)
然后将其中的utf-8修改为GB2312
再刷新刚打开的页面,发现字符显示已经是乱码
所以对于网页或者传输而言,你要知道你传输的字符或者文件的编码格式,然后由你自己告诉对方你的编码格式,如果你告诉别人的编码方式和实际文件的编码格式不一致,那么结果很可能是两个字:乱码。
四、 常用字符编码标准
ID | 标准名称 | 作用 | 备注 |
1 | 标准ASCII | 特指0-127共128个字符 | 只适用于纯英语环境 |
2 | Unicode | 为世界上每个字符分配一个编码 | 只规定了编号,未规定存储和传输方式 |
3 | UCS2 | Unicode编码的一种实现 使用两个字节表示一个字符 | 实际是Unicode的一个子集 通常所说的Unicode就指UCS2 |
4 | UTF8 | Unicode编码存储的一种实现 字节可变 | |
5 | GB2312 | 又称GB2312-80 | |
6 | GBK |
在C++体系中,字符类型本质上只有char和wchar_t两种,其他的要么只是封装,比如string封装了char数组,wstring封装了wchar_t数组,要么是为了兼容不同的语言或组件,比如CString是MFC框架下的字符串,_bstr_t是COM组件中的字符串。下表列出了常用的字符类型。
分类 | ID | 名称 | 备注 |
标准C++ | char | 单字节 | |
wchar_t | 宽字节,在string.h中定义 实际是unsigned short 需使用wcs前缀的函数处理wchar_t wchar_t* myStr=L"测试"; | ||
string | |||
wstring | |||
VC | CHAR | 等同于char | |
WCHAR | 等同于wchar_t | ||
TCHAR | 根据_UNICODE宏,确定当前表示的是ANSI还是Unicode 所以应配合_T使用初始化字符串 且应使用以_tcs为前缀的函数 | ||
_T TEXT _TEXT | 三个作用一样, 根据环境决定是ASCII还是Unicode | ||
L | 将字符串变成Unicode | ||
MFC | CString | MFC字符串 | |
COM相关 | OLECHAR | 不同环境下自动为 WCHAR或CHAR | |
BSTR | 是一个有长度有前缀和null结束符的OLECHAR数组 是COM中默认的字符串格式 | ||
_bstr_t | 是对BSTR的封装的类 实际是一个智能指针 为实现和LPCSTR和BSTR才有的 | ||
CComBSTR | ATL中的类 是对BSTR类型的分装 | ||
VARIANT | 可变类型 | ||
_variant_t | 是对VARIAN的封装,类似于_bstr_t对于BSTR的封装 | ||
COleVariant | 是对VARIANT的封装 |
typedef WCHAR *PWCHAR,*LPWCH, *PWCH;
typedef CONST WCHAR *LPCWCH, *PCWCH;
typedef _Null_terminated_WCHAR *NWPSTR, *LPWSTR, *PWSTR;
typedef _Null_terminated_ PWSTR *PZPWSTR;
typedef _Null_terminated_ CONST PWSTR *PCZPWSTR;
typedef _Null_terminated_ WCHAR UNALIGNED *LPUWSTR, *PUWSTR;
typedef _Null_terminated_ CONST WCHAR *LPCWSTR, *PCWSTR;
typedef _Null_terminated_ PCWSTR *PZPCWSTR;
typedef _Null_terminated_ CONST PCWSTR *PCZPCWSTR;
typedef _Null_terminated_ CONST WCHAR UNALIGNED *LPCUWSTR, *PCUWSTR;
typedef _NullNull_terminated_WCHAR *PZZWSTR;
typedef _NullNull_terminated_ CONST WCHAR *PCZZWSTR;
typedef _NullNull_terminated_ WCHAR UNALIGNED *PUZZWSTR;
typedef _NullNull_terminated_ CONST WCHAR UNALIGNED *PCUZZWSTR;
typedef WCHAR *PNZWCH;
typedef CONST WCHAR *PCNZWCH;
typedef WCHAR UNALIGNED *PUNZWCH;
typedef CONST WCHAR UNALIGNED *PCUNZWCH;
typedef CONST WCHAR*LPCWCHAR, *PCWCHAR;
typedef CONST WCHAR UNALIGNED *LPCUWCHAR, *PCUWCHAR;
//
// UCS (Universal Character Set) types
//
typedef unsigned longUCSCHAR;
#ifndef _TCHAR_DEFINED
typedef WCHAR TCHAR, *PTCHAR;
typedef WCHAR TBYTE , *PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */
typedef LPWCH LPTCH, PTCH;
typedef LPCWCH LPCTCH, PCTCH;
typedef LPWSTR PTSTR, LPTSTR;
typedef LPCWSTR PCTSTR, LPCTSTR;
typedef LPUWSTR PUTSTR, LPUTSTR;
typedef LPCUWSTR PCUTSTR, LPCUTSTR;
typedef LPWSTR LP;
typedef PZZWSTR PZZTSTR;
typedef PCZZWSTR PCZZTSTR;
typedef PUZZWSTR PUZZTSTR;
typedef PCUZZWSTR PCUZZTSTR;
typedef PZPWSTR PZPTSTR;
typedef PNZWCH PNZTCH;
typedef PCNZWCH PCNZTCH;
typedef PUNZWCH PUNZTCH;
typedef PCUNZWCH PCUNZTCH;
#define __TEXT(quote) L##quote // r_winnt
看了这么多字符类型,只能说C\C++语言体系(不仅仅包括语言本身,还包括配套类库)的统一性还停留在上个实际的水平,对于这种奇奇怪怪的类型,遇到的时候去go to definition就够了。时间终将会逐渐淘汰这些历史过度的产物。
六、 字符函数总结
分类 | 名称 | 备注 |
常用字符串操作 | str开头的函数 如strcat,连接字符串 strcpy,复制字符串 strcmp,比较字符串,区分大小写 stricmp,比较字符串,不区分大小写 | 对char类型字符串的处理 |
wcs开头的函数 如wcscmp功能和strcmp功能一样,只是wcscmp用于wchar_t | 对wchar_t类型字符串的处理 | |
单字节和宽字节转换 | wcstombs_s | |
mbstowcs_s | ||
MultiByteToWideChar | 从char转换成wchat_t | |
WideCharToMultiByte | 从wchat_t转换成char | |
ConvertBSTRToString | 从BSTR转换成string | |
ConvertStringToBSTR | 从string转换成BSTR | |
数字和字符串之间转换 | atoi | |
atol | ||
atof | ||
strtod | ||
strtol | ||
strtoul | ||
sprintf | ||
stream | ||
stringstream | ||
ostringstream |
1.VS工程编码
VS2008
2.UTF8编码存储文件
3.xml
4. 文件读写
5.多语言
6.http
7.哈夫曼编码
八、 参考文献及博客
1. 百度百科:ASCII
http://baike.baidu.com/link?url=fpRp_IBr7z9azzwOUgwJM2cszeFGJxrS-KB_GB42i8ETkAwjkoR-JHEAHIRzdE7BZBCwqJd7QP7v9v25Xb7gJa
2. 维基百科:ISO/IEC646
https://wuu.wikipedia.org/wiki/ISO/IEC_646
3. 字符编码
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
4. Unicode组织
http://www.unicode.org/
5. The Absolute Minimum Every Software Developer Absolutely, PositivelyMust Know About Unicode and Character Sets (No Excuses!)
http://www.joelonsoftware.com/articles/Unicode.html
6. codePage和charset
/article/4661419.html
7. 程序员趣味读物:谈谈Unicode编码
/article/9296337.html
8. 字符编码(ucs2_+unicode_+utf8_+gb2312)
http://blog.sina.com.cn/s/blog_958a07d0010136y1.html
9. UTF-8编码规则
/article/4921541.html
10. Unicode转UTF8
/article/9932275.html
11. UTF8最好不要带BOM
/article/4774579.html
12. Unicode VS Multibyte
http://blog.codingnow.com/2006/03/unicode_vs_multibyte.html
13.
Unicode(UTF-8,UTF-16)令人混淆的概念
/article/6061801.html
14.
简单几句话总结Unicode,UTF-8和UTF-16
/article/7164511.html
15. How to: Convert BetweenVarious String Types
https://msdn.microsoft.com/en-US/library/ms235631
16. C++中的wchar_t
/article/6491263.html
17. C++官网
http://www.cplusplus.com/
18. BSTR类型跟_bstr_t区别
https://www.douban.com/note/188555222/
19.
搞清楚VC++中的char,wchar_t,TCHAR
/article/8786766.html
20.
关于char,wchar_t, TCHAR, _T(),L,宏 _T、TEXT,_TEXT、L
/article/6395232.html
21. CString与LPCWSTR、LPSTR、char*、LPWSTR等类型的转换
/article/3627260.html
22.
多字符集(ANSI)和UNICODE及字符串处理方式准则
/article/9005242.html
23.
BIG5编码, GB编码(GB2312, GBK,...), Unicode编码,
UTF8,WideChar, MultiByte, Char 说明与区别
/article/1563271.html
24.
GB2312, BIG5,UTF8, Unicode之间的互换
/article/1563444.html
25. ANSI、UNICODE、UTF-8、GB2312、GBK、DBCS、UCS的区别和由来
http://blog.chinaunix.net/uid-20743151-id-326455.html
九、 附录
1.ASCII码表
Bin | Dec | Hex | 缩写/字符 | 解释 |
0000 0000 | 0 | 00 | NUL(null) | 空字符 |
0000 0001 | 1 | 01 | SOH(start of headline) | 标题开始 |
0000 0010 | 2 | 02 | STX (start of text) | 正文开始 |
0000 0011 | 3 | 03 | ETX (end of text) | 正文结束 |
0000 0100 | 4 | 04 | EOT (end of transmission) | 传输结束 |
0000 0101 | 5 | 05 | ENQ (enquiry) | 请求 |
0000 0110 | 6 | 06 | ACK (acknowledge) | 收到通知 |
0000 0111 | 7 | 07 | BEL (bell) | 响铃 |
0000 1000 | 8 | 08 | BS (backspace) | 退格 |
0000 1001 | 9 | 09 | HT (horizontal tab) | 水平制表符 |
0000 1010 | 10 | 0A | LF (NL line feed, new line) | 换行键 |
0000 1011 | 11 | 0B | VT (vertical tab) | 垂直制表符 |
0000 1100 | 12 | 0C | FF (NP form feed, new page) | 换页键 |
0000 1101 | 13 | 0D | CR (carriage return) | 回车键 |
0000 1110 | 14 | 0E | SO (shift out) | 不用切换 |
0000 1111 | 15 | 0F | SI (shift in) | 启用切换 |
0001 0000 | 16 | 10 | DLE (data link escape) | 数据链路转义 |
0001 0001 | 17 | 11 | DC1 (device control 1) | 设备控制1 |
0001 0010 | 18 | 12 | DC2 (device control 2) | 设备控制2 |
0001 0011 | 19 | 13 | DC3 (device control 3) | 设备控制3 |
0001 0100 | 20 | 14 | DC4 (device control 4) | 设备控制4 |
0001 0101 | 21 | 15 | NAK (negative acknowledge) | 拒绝接收 |
0001 0110 | 22 | 16 | SYN (synchronous idle) | 同步空闲 |
0001 0111 | 23 | 17 | ETB (end of trans. block) | 传输块结束 |
0001 1000 | 24 | 18 | CAN (cancel) | 取消 |
0001 1001 | 25 | 19 | EM (end of medium) | 介质中断 |
0001 1010 | 26 | 1A | SUB (substitute) | 替补 |
0001 1011 | 27 | 1B | ESC (escape) | 换码(溢出) |
0001 1100 | 28 | 1C | FS (file separator) | 文件分割符 |
0001 1101 | 29 | 1D | GS (group separator) | 分组符 |
0001 1110 | 30 | 1E | RS (record separator) | 记录分离符 |
0001 1111 | 31 | 1F | US (unit separator) | 单元分隔符 |
0010 0000 | 32 | 20 | (space) | 空格 |
0010 0001 | 33 | 21 | ! | |
0010 0010 | 34 | 22 | " | |
0010 0011 | 35 | 23 | # | |
0010 0100 | 36 | 24 | $ | |
0010 0101 | 37 | 25 | % | |
0010 0110 | 38 | 26 | & | |
0010 0111 | 39 | 27 | ' | |
0010 1000 | 40 | 28 | ( | |
0010 1001 | 41 | 29 | ) | |
0010 1010 | 42 | 2A | * | |
0010 1011 | 43 | 2B | + | |
0010 1100 | 44 | 2C | , | |
0010 1101 | 45 | 2D | - | |
0010 1110 | 46 | 2E | . | |
00101111 | 47 | 2F | / | |
00110000 | 48 | 30 | 0 | |
00110001 | 49 | 31 | 1 | |
00110010 | 50 | 32 | 2 | |
00110011 | 51 | 33 | 3 | |
00110100 | 52 | 34 | 4 | |
00110101 | 53 | 35 | 5 | |
00110110 | 54 | 36 | 6 | |
00110111 | 55 | 37 | 7 | |
00111000 | 56 | 38 | 8 | |
00111001 | 57 | 39 | 9 | |
00111010 | 58 | 3A | : | |
00111011 | 59 | 3B | ; | |
00111100 | 60 | 3C | < | |
00111101 | 61 | 3D | = | |
00111110 | 62 | 3E | > | |
00111111 | 63 | 3F | ? | |
01000000 | 64 | 40 | @ | |
01000001 | 65 | 41 | A | |
01000010 | 66 | 42 | B | |
01000011 | 67 | 43 | C | |
01000100 | 68 | 44 | D | |
01000101 | 69 | 45 | E | |
01000110 | 70 | 46 | F | |
01000111 | 71 | 47 | G | |
01001000 | 72 | 48 | H | |
01001001 | 73 | 49 | I | |
01001010 | 74 | 4A | J | |
01001011 | 75 | 4B | K | |
01001100 | 76 | 4C | L | |
01001101 | 77 | 4D | M | |
01001110 | 78 | 4E | N | |
01001111 | 79 | 4F | O | |
01010000 | 80 | 50 | P | |
01010001 | 81 | 51 | Q | |
01010010 | 82 | 52 | R | |
01010011 | 83 | 53 | S | |
01010100 | 84 | 54 | T | |
01010101 | 85 | 55 | U | |
01010110 | 86 | 56 | V | |
01010111 | 87 | 57 | W | |
01011000 | 88 | 58 | X | |
01011001 | 89 | 59 | Y | |
01011010 | 90 | 5A | Z | |
01011011 | 91 | 5B | [ | |
01011100 | 92 | 5C | \ | |
01011101 | 93 | 5D | ] | |
01011110 | 94 | 5E | ^ | |
01011111 | 95 | 5F | _ | |
01100000 | 96 | 60 | ` | |
01100001 | 97 | 61 | a | |
01100010 | 98 | 62 | b | |
01100011 | 99 | 63 | c | |
01100100 | 100 | 64 | d | |
01100101 | 101 | 65 | e | |
01100110 | 102 | 66 | f | |
01100111 | 103 | 67 | g | |
01101000 | 104 | 68 | h | |
01101001 | 105 | 69 | i | |
01101010 | 106 | 6A | j | |
01101011 | 107 | 6B | k | |
01101100 | 108 | 6C | l | |
01101101 | 109 | 6D | m | |
01101110 | 110 | 6E | n | |
01101111 | 111 | 6F | o | |
01110000 | 112 | 70 | p | |
01110001 | 113 | 71 | q | |
01110010 | 114 | 72 | r | |
01110011 | 115 | 73 | s | |
01110100 | 116 | 74 | t | |
01110101 | 117 | 75 | u | |
01110110 | 118 | 76 | v | |
01110111 | 119 | 77 | w | |
01111000 | 120 | 78 | x | |
01111001 | 121 | 79 | y | |
01111010 | 122 | 7A | z | |
01111011 | 123 | 7B | { | |
01111100 | 124 | 7C | | | |
01111101 | 125 | 7D | } | |
01111110 | 126 | 7E | ~ | |
01111111 | 127 | 7F | DEL (delete) | 删除 |
相关文章推荐
- Android开发:ViewPage介绍&使用教程
- MYSQL内存--------启动mysql缓存机制,实现命中率100% 转
- Bootstrap 网格系统(Grid System)的工作原理 - 媒体查询
- SQL Server日期与字符串之间的转换
- maxContainerCapability 设置不足
- php7新特性
- 在O(1)时间删除链表结点
- (java)Best Time to Buy and Sell Stock系列
- 如何查看 JAR 包的源代码
- WebView设置文本内容字体的大小以及颜色
- 相机中白平衡的算法模拟实现
- AR增强现实功能,也能玩转智能家居?
- Qt配置文件中文读写小例子
- css样式定义标记(. # html)
- 八大排序之选择排序
- 七大排序算法
- Runtime 交换方法
- 在VC中如何找到崩溃的源头(二)
- 借款人想通过Netaji货币还款
- 推荐Huploadify实现上传图片或文件