char
可被应用于所有8bit以及8bit以下的字符集,例如: US-ASCII,ISO-Latin-1和ISO-Latin-9以及UTF-8.
char16_t
可被用于UCS-2,也可被用于UTF-16的code unit(代码单元).
char32_t
可被用于UCS-4/UTF-32.
wchar_t
它通常等价于char16_t或者char32_t.
US-ASCII
7-bit字符集,于1963年完成标准化,用于电传打字机和其他设备,最开始的16个字符是不可打印的。
ISO-Latin-1或ISO-8859-1
这是一个8bit的字符集,于1987年完成标准提供西欧语言的所有字符,这个字符集也是下面所有字符集的基础.
UCS-2
这是一个16bit的定长字符集(2byte),提供Universal Character Set(全球字符集)和Unicode(统一码)中最重要的65536个字符.
UTF-8
这是个multi-byte字符集,使用1-4个8bit值,用来表现Universal Character Set(全球字符集)和Unicode(统一码)的所有字符.主要被广泛的应用于万维网(world wide web).
UTF-16
这也是一个multi-byte字符集,使用1-2 code unit(每个16bit),用来表现Universal Character Set(全球字符集)和Unicode(同意码)之所有标准化字符.
UCS-4或UTF-32
这个32bit的定长字符集(4byte),提供Unversal Character Set(全球字符集)和Unicode(统一码)之所有标准化字符.
多字节和宽字符文本:
1,在多字节(Multibyte)表示法中,字符所用的byte是变动的。一个1-byte字符(例如 ISO-Latin-1字符)后面再跟1个,2个或者3个byte,例如中文或者日文。
2,宽字符(wide-character)表示法,字符所用的byte数目固定,与其所表示的字符无关,典型的byte个数是2个或者4个.
在我们了解Unicode之前首先了解一下GB,GBK等待国产字符集.
作者:Tuxify
链接:https://www.zhihu.com/question/19677619/answer/12616362
1, GB2312-80
GB 2312 或 GB 2312-80 是中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,又称GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB 2312。
GB 2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个字符。
- GB 2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。
- 对于人名、古汉语等方面出现的罕用字,GB 2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现。
GB2312对任意一个图形字符都采用两个字节表示,并对所收汉字进行了“分区”处理,每区含有94个汉字/符号,分别对应第一字节和第二字节。这种表示方式也称为区位码。
- 01-09区为特殊符号。
- 16-55区为一级汉字,按拼音排序。
- 56-87区为二级汉字,按部首/笔画排序。
10-15区及88-94区则未有编码。
GB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。
2 ,GBK
GBK即汉字内码扩展规范,K为汉语拼音 Kuo Zhan(扩展)中“扩”字的声母。英文全称Chinese Internal Code Specification。
GBK共收入21886个汉字和图形符号,包括:
- GB2312中的全部汉字、非汉字符号。
- BIG5中的全部汉字。
- 与ISO 10646相应的国家标准GB13000中的其它CJK汉字,以上合计20902个汉字。
- 其它汉字、部首、符号,共计984个。
GBK向下与GB2312 完全兼容,向上支持ISO 10646国际标准,在前者向后者过渡过程中起到的承上启下的作用。
GBK 采用双字节表示,总体编码范围为8140-FEFE之间,首字节在81-FE之间,尾字节在40-FE之间,剔除XX7F一条线。GBK编码区分三部分:
- 汉字区 包括
GBK/2:0xB0A1-F7FE, 收录GB2312汉字6763个,按原序排列;
GBK/3:0x8140-A0FE,收录CJK汉字6080个;
GBK/4:0xAA40-FEA0,收录CJK汉字和增补的汉字8160个。
- 图形符号区 包括
GBK/1:0xA1A1-A9FE,除GB2312的符号外,还增补了其它符号
GBK/5:0xA840-A9AO,扩除非汉字区。
- 用户自定义区
GBK区域中的空白区,用户可以自己定义字符。
3 ,GB18030
GB 18030,全称:国家标准GB 18030-2005《信息技术中文编码字符集》,是中华人民共和国现时最新的内码字集,是GB 18030-2000《信息技术信息交换用汉字编码字符集基本集的扩充》的修订版。
GB 18030与GB 2312-1980完全兼容,与GBK基本兼容,支持GB 13000及Unicode的全部统一汉字,共收录汉字70244个。
- 与 UTF-8 相同,采用多字节编码,每个字可以由1个、2个或4个字节组成。
- 编码空间庞大,最多可定义161万个字符。
- 支持中国国内少数民族的文字,不需要动用造字区。
- 汉字收录范围包含繁体汉字以及日韩汉字
GB18030 编码是一二四字节变长编码。
- 单字节,其值从0到0x7F,与 ASCII 编码兼容。
- 双字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x40到0xFE(不包括0x7F),与 GBK标准基本兼容。
- 四字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x30到0x39,第三个字节从0x81到0xFE,第四个字节从0x30到0x39。
ASCII,GB(K),Unicode的区别与联系:
链接:https://www.zhihu.com/question/19677619/answer/27516663
很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物。他们看到8个开关状态是好的,于是他们把这称为”字节“。再后来,他们又做了一些可以处理这些字节的机器,机器开动了,可以用字节来组合出很多状态,状态开始变来变去。他们看到这样是好的,于是它们就这机器称为”计算机“。
开始计算机只在美国用。八位的字节一共可以组合出256(2的8次方)种不同的状态。 他们把其中的编号从0开始的32种状态分别规定了特殊的用途,一但终端、打印机遇上约定好的这些字节被传过来时,就要做一些约定的动作。遇上0×10, 终端就换行,遇上0×07, 终端就向人们嘟嘟叫,例好遇上0x1b, 打印机就打印反白的字,或者终端就用彩色显示字母。他们看到这样很好,于是就把这些0×20以下的字节状态称为”控制码”。他们又把所有的空 格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号,这样计算机就可以用不同字节来存储英语的文字了。大家看到这样,都感觉 很好,于是大家都把这个方案叫做ANSI 的”Ascii”编码(American Standard Code for Information Interchange,美国信息互换标准代码)。当时世界上所有的计算机都用同样的ASCII方案来保存英文文字。
后来,就像建造巴比伦塔一样,世界各地的都开始使用计算机,但是很多国家用的不是英文,他们的字母里有许多是ASCII里没有的,为了可以在计算机保存他们的文字,他们决定采用 127号之后的空位来表示这些新的字母、符号,还加入了很多画表格时需要用下到的横线、竖线、交叉等形状,一直把序号编到了最后一个状态255。从128 到255这一页的字符集被称”扩展字符集“。从此之后,贪婪的人类再没有新的状态可以用了,美帝国主义可能没有想到还有第三世界国家的人们也希望可以用到计算机吧!
等中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民,我们不客气地把那些127号之后的奇异符号们直接取消掉, 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。 中国人民看到这样很不错,于是就把这种汉字方案叫做 “GB2312“。GB2312 是对 ASCII 的中文扩展。
但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来,特别是某些很会麻烦别人的国家领导人。于是我们不得不继续把 GB2312 没有用到的码位找出来老实不客气地用上。 后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK包括了GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。 后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK扩成了 GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。 中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 “DBCS“(Double Byte Charecter Set 双字节字符集)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。那时候凡是受过加持,会编程的计算机僧侣 们都要每天念下面这个咒语数百遍: “一个汉字算两个英文字符!一个汉字算两个英文字符……”
因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,连大陆和台湾这样只相隔了150海里,使用着同一种语言的兄弟地区,也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字,就必须装上一个”汉字系统”,专门用来处理汉字的显示、输入的问题,但是那个台湾的愚昧封建人士写的算命程序就必须加装另一套支持 BIG5 编码的什么”倚天汉字系统”才可以用,装错了字符系统,显示就会乱了套!这怎么办?而且世界民族之林中还有那些一时用不上电脑的穷苦人民,他们的文字又怎么办? 真是计算机的巴比伦塔命题啊!
正在这时,大天使加百列及时出现了——一个叫 ISO (国际标谁化组织)的国际组织决定着手解决这个问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号 的编码!他们打算叫它”Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “unicode“。
unicode开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是 ISO 就直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于ASCII里的那些“半角”字符,unicode包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。
这时候,从旧社会里走过来的程序员开始发现一个奇怪的现象:他们的strlen函数靠不住了,一个汉字不再是相当于两个字符了,而是一个!是的,从unicode开始,无论是半角的英文字母,还是全角的汉字,它们都是统一的”一个字符“!同时,也都是统一的”两个字节“,请注意”字符”和”字节”两个术语的不同,“字节”是一个8位的物理存贮单元,而“字符”则是一个文化相关的符号。在unicode中,一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。
unicode同样也不完美,这里就有两个的问题,一个是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储空间来说是极大的浪费,文本文件的大小会因此大出二三倍,这是难以接受的。
unicode在很长一段时间内无法推广,直到互联网的出现,为解决unicode如何在网络上传输的问题,于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。UTF-8就是在互联网上使用最广的一种unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。
UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度,当字符在ASCII码的范围时,就用一个字节表示,保留了ASCII字符一个字节的编码做为它的一部分,注意的是unicode一个中文字符占2个字节,而UTF-8一个中文字符占3个字节)。从unicode到uft-8并不是直接的对应,而是要过一些算法和规则来转换。
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
—————————————————————–
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Notice: 无论是UTF-8,UTF-16,还是UTF-32,亦或者是UCS-2,UCS-4都是属于Unicode.
Unicode和多字节(Multi-byte):
计算机中的字符并不是保存为图像,每个字符都是通过一个编码来表示,而每个字符究竟使用哪个编码表示,取决于所使用的字符集(charset)。
在最初的时候世界上只有一种字符集-ASCII字符集,它使用7bits表示一个字符,总共可以表示128个字符,之后又进行扩展使用8bits表示一个字符,总共可以表示256个字符。
到了后来计算机再各个国家开始被应用ASCII显然不能满足其他国家需求。于是各个国家在ASCII标准上制定自己的字符集,这些从ASCII标准上派生出来的字符集通常被称为ASCII字符集,他们的正式名字应该是MBCS(Multi-byte-character-system)。这些派生字符集的特点是他们使用大于128的做为一个Leading byte,和紧跟在Leading byte后面的第二个(甚至第三个)byte共同组成一个世纪的字符编码.比如我们国家的GB-2312.
例如在GB-2312字符集中,“连通”的编码为C1 AC CD A8,其中C1和CD就是Leading Byte。前127个编码为标准ASCII保留;
例如’0‘的编码是30H(30H表示十六进制的30)。软件在读取时,如果看到30H,知道它小于128就是标准ASCII,表示“0”,看到C1大于128就知道它后面还有另外的编码,因此C1 AC一同构成一个整个的编码,在GB-2312字符集中表示“连”。
由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,提出了Unicode字符集,它固定使用16 bits(两个字节、一个字)来表示一个字符,共可以表示65536个字符。将世界上几乎所有语言的常用字符收录其中,方便了信息交流。标准的Unicode称为UTF-16。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输,出现了UTF-8,使用类似MBCS的方式对Unicode进行编码。注意UTF-8是编码,它属于Unicode字符集。Unicode字符集有多种编码形式,而ASCII只有一种,大多数MBCS(包括GB-2312)也只有一种。Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题 (implantation head-ache's),尤其在那些基于网络的应用中。已有的软件必须做大量的工作来处理16位的数据。
因此,Unicode用一些基本的保留字符制定了三套编码方式它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列来编码的,用一个或几个字节(byte)来表示一个字符。这种方式的最大好处是:UTF-8保留了ASCII字符的编码做为它的一部分。例如,在UTF-8和ASCII中,‘A'的编码都是0x41。 UTF-16和UTF-32分别是Unicode的16位和32位编码方式。考虑到最初的目的,通常说的Unicode就是指UTF-16。
Notice: 对于UTF-16和UTF-32会在完整的字符序列一开始放一个byte order mark(BOM),用于标示它使用的是big-endian(此为默认)还是little-endian.
Big-endian和Little-endian:
Big endian和Little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C 49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是Big endian。还是将49写在前面,就是Little endian。
“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位.
当一个软件打开一个文档的时候首先要确定该文档所用的字符集是什么,下面的这种插入字符集标识的方法称为BOM:
1,如果是UTF-8会在文档的开头插入一个不显示的字符:EF BB BF
2,如果是UTF-16/UCS-2(Big-endian)会在文档的开头插入一个不可见的字符:FE FF
如果是UTF-16/UCS-2(Little-endian)会在文档的开头插入一个不可见的字符:FF FE
3,如果是UTF-32/UCS-4(Big-endian)会在文档的开头插入一个不可见的字符:FE FF 00 00
如果是UTF-32/UCS-4(Little-endian)会在文档的开头插入一个不可见的字符:00 00 FF FE
4,如果是GB,GBK是不会插入任何标志因此程序只能靠蒙.
<-----------------------------------我是分割线---------------------------------------->
我们已经了解了这么多编码了下面开始程序相关了:
在C/C++中我们必须明确两个概念:
源码字符集(The source character set) | 源码文件是使用哪种字符集保存的 |
执行字符集(The excution character set) | 执行程序时候内存中的字符编码 |
源文件字符集如何设置? | 正如前面介绍的通过在文件开头插入一个标志 |
执行字符集如何设置? | C++是通过设置std::locale |
注意如果是MSVS2015如果源文件字符集被使用utf那么程序的执行字符集也被默认使用utf8!
不需要再手动设置std::locale了.
也就是说:
//source.cpp Notice:该cpp文件已经被用utf-8(BOM)的方式保存.
#include <iostream>
int main()
{
std::basic_string<char> str("十花"); //这两个字符串其实是一致的.无论用不用u8标识.
std::basic_string<char> str(u8"十花");
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/2516597/blog/751495