背景: C++的项目,字符编码是一个大坑,不同平台之间的编码往往不一样,如果不同编码格式用一套字符读取格式读取就会出现乱码。 所以本文旨在对字符编码的知识做一个大概的梳理。
字符编码定义
计算机是以二进制的形式来存储数据的,它只认识 0 和 1 两个数字。我们在屏幕上看到的文字,在存储之前都被转换成了二进制(0和1序列),在显示时也要根据二进制找到对应的字符, 所以特定的文字必然对应着固定的二进制 。
那怎样将文字与二进制对应起来呢 ? 这就需要有一套规范,计算机公司和软件开发者都必须遵守,这样的一套规范就称为字符集(Character Set)或者字符编码(Character Encoding)。
严格来说,字符集和字符编码不是一个概念,字符集定义了文字和二进制的对应关系,为字符分配了唯一的编号,而字符编码规定了如何将文字的编号存储到计算机中。我们暂时先不讨论这些细节,姑且认为它们是一个概念
各种字符编码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JXfyJUgE-1644907769659)(C:\Users\86157\AppData\Roaming\Typora\typora-user-images\1644906042899.png)]
-
ASCII码
计算机是美国人发明的,他们首先要考虑的问题是,如何将二进制和英文字母对应起来,所以ASCII码由此诞生。 ASCII包括128个字符,包含了英⽂字⺟的大小写以及⼀些其他控制符。
-
GBK
编码
计算机是美国人发明的,它使用的是 ASCII 编码,只能显示英文字符,对汉语、韩语、日语、法语、德语等其它国家的字符无能为力。
为了让本国公民也能使用上计算机,各个国家(地区)也开始效仿 ASCII,开发了自己的字符编码。中文编码也随即出现: GB2312
-->GBK
--> GB18030
是中文编码的三套方案,出现的时间从早到晚,收录的字符数目依次增加,并且向下兼容。
-
Unicode
世界各国家都根据自己的语言文化开发了不同的字符编码,不具有通用性,在一种编码下开发的软件或者编写的文档,拿到另一种编码下就会失效,必须提前使用程序转码,非常麻烦。 人们迫切希望有一种编码能够统一世界各地的字符,计算机只要安装了这一种字编码,就能支持使用世界上所有的文字。
在这种呼吁下,Unicode 诞生了。Unicode 也称为统一码、万国码 。 看名字就知道,Unicode 希望统一所有国家的字符编码。但Unicode 也只定义了符号的⼆进制表示,没有规定如何存储。 UTF-8
、UTF-16
、UTF-32
是基于Unicode的具体存储⽅式。
-
UTF-8
:一种变长的编码方案,使用 1~6 个字节来存储;
-
UTF-32
:一种固定长度的编码方案,不管字符编号大小,始终使用 4 个字节来存储;
-
UTF-16
:介于 UTF-8
和 UTF-32
之间,使用 2 个或者 4 个字节来存储,长度既固定又可变。
这三种方式的优缺点:
-
UTF-8
使用尽量少的字节来存储一个字符,不但能够节省存储空间,而且在网络传输时也能节省流量,所以很多纯文本类型的文件(例如各种编程语言的源文件、各种日志文件和配置文件等)以及绝大多数的网页(例如百度、新浪、163等)都采用UTF-8
编码。
UTF-8
的缺点是效率低,不但在存储和读取时都要经过转换,而且在处理字符串时也非常麻烦。
-
UTF-32
是“以空间换效率”,正好弥补了UTF-8
的缺点,UTF-32
的优势就是效率高:UTF-32
在存储和读取字符时不需要任何转换,在处理字符串时也能最快速地定位字符。
UTF-32
的缺点也很明显,就是太占用存储空间了,在网络传输时也会消耗很多流量。
-
UTF-16
可以看做是 UTF-8
和UTF-32
的折中方案,它平衡了存储空间和处理效率的矛盾。对于常用的字符,用两个字节存储足以,这个时候 UTF-16
是不需要转换的,直接存储字符的编码值即可。
宽字符与窄字符
- 有的编码方式采用 1~n 个字节存储,是变长的,例如
UTF-8
、GB2312
、GBK
等;如果一个字符使用了这种编码方式,我们就将它称为多字节字符,或者窄字符。
- 有的编码方式是固定长度的,不管字符编号大小,始终采用 n 个字节存储,例如
UTF-32
、UTF-16
等;如果一个字符使用了这种编码方式,我们就将它称为宽字符。
- Unicode 字符集可以使用窄字符的方式存储,也可以使用宽字符的方式存储;
GB2312
、GBK
、Shift-JIS
等国家编码一般都使用窄字符的方式存储;ASCII 只有一个字节,无所谓窄字符和宽字符。
Visual C++6.0用的是多字节编码;
Virtual Studio 2010 默认使用的是Unicode编码。
MFC
有两种编码方式,Unicode和多字节并且可以设置切换。切换方法是打开项目属性页,常规项对应的字符集中可切换编码方式。
c/c++中的字符与字符串
-
Windows使用两种字符集ANSI和UNICODE,前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。而后者是双字节方式,方便处理双字节字符。
-
在Visual Studio中编写C++代码时,该如何指定字符串的编码呢?其实很简单,使用双引号括住的字符串,使用的就是ANSI窄字节编码;使用L+双引号括住的字符串,使用的就是Unicode宽字节编码
char* pStr = "This is a Test."; // ANSI编码
WCHAR* pWStr = L"This is a Test."; // Unicode宽字节编码
也可以使用**_T宏**定义来指定字符串的编码格式: _T 是一个宏,如果项目使用了Unicode字符集,则自动在字符串前面加上L,否则字符串不变。因此用_T来保证兼容性。
TCHAR* pStr = _T("This is a Test.");
也可以在属性页设置字符集:右键项目->配置属性->常规->字符集
-
c/c++中的字符与字符串