C++字符编码

在计算机中,所有数据都是以二进制数的形式存储的,字符char也不例外。为了表示字符,我们需要建立一套“字符集”,规定每个字符和二进制数之间的一一对应关系。有了字符集之后,计算机就可以通过查表完成二进制数到字符的转换。

「ASCII码」是最早出现的字符集,全称为“美国标准信息交换代码”。它使用7位二进制数(即一个字节的低7位)表示一个字符,最多能够表示128个不同的字符。如图3-6所示,ASCII码包括英文字母的大小写、数字0~9、一些标点符号,以及一些控制字符(如换行符和制表符)。

图3-6ASCII码

然而,ASCII码仅能够表示英文。随着计算机的全球化,诞生了一种能够表示更多语言的字符集「EASCII」。它在ASCII的7位基础上扩展到8位,能够表示256个不同的字符。

在世界范围内,陆续出现了一批适用于不同地区的EASCII字符集。这些字符集的前128个字符统一为ASCII码,后128个字符定义不同,以适应不同语言的需求。

后来人们发现,EASCII码仍然无法满足许多语言的字符数量要求。比如汉字大约有近十万个,光日常使用的就有几千个。中国国家标准总局于1980年发布了「GB2312」字符集,其收录了6763个汉字,基本满足了汉字的计算机处理需要。

然而,GB2312无法处理部分的罕见字和繁体字。「GBK」字符集是在GB2312的基础上扩展得到的,它共收录了21886个汉字。在GBK的编码方案中,ASCII字符使用一个字节表示,汉字使用两个字节表示。

随着计算机的蓬勃发展,字符集与编码标准百花齐放,而这带来了许多问题。一方面,这些字符集一般只定义了特定语言的字符,无法在多语言环境下正常工作。另一方面,同一种语言也存在多种字符集标准,如果两台电脑安装的是不同的编码标准,则在信息传递时就会出现乱码。

那个时代的研究人员就在想:如果推出一个足够完整的字符集,将世界范围内的所有语言和符号都收录其中,不就可以解决跨语言环境和乱码问题了吗?在这种想法的驱动下,一个大而全的字符集Unicode应运而生。

「Unicode」的全称为“统一字符编码”,理论上能容纳一百多万个字符。它致力于将全球范围内的字符纳入到统一的字符集之中,提供一种通用的字符集来处理和显示各种语言文字,减少因为编码标准不同而产生的乱码问题。

自1991年发布以来,Unicode不断扩充新的语言与字符。截止2022年9月,Unicode已经包含149186个字符,包括各种语言的字符、符号、甚至是表情符号等。在庞大的Unicode字符集中,常用的字符占用2字节,有些生僻的字符占3字节甚至4字节。

Unicode是一种字符集标准,本质上是给每个字符分配一个编号(称为“码点”),但它并没有规定在计算机中如何存储这些字符码点。我们不禁会问:当多种长度的Unicode码点同时出现在同一个文本中时,系统如何解析字符?例如给定一个长度为2字节的编码,系统如何确认它是一个2字节的字符还是两个1字节的字符?

对于以上问题,一种直接的解决方案是将所有字符存储为等长的编码。如图3-7所示,“Hello”中的每个字符占用1字节,“算法”中的每个字符占用2字节。我们可以通过高位填0,将“Hello算法”中的所有字符都编码为2字节长度。这样系统就可以每隔2字节解析一个字符,恢复出这个短语的内容了。

图3-7Unicode编码示例

然而ASCII码已经向我们证明,编码英文只需要1字节。若采用上述方案,英文文本占用空间的大小将会是ASCII编码下大小的两倍,非常浪费内存空间。因此,我们需要一种更加高效的Unicode编码方法。

目前,UTF-8已成为国际上使用最广泛的Unicode编码方法。它是一种可变长的编码,使用1到4个字节来表示一个字符,根据字符的复杂性而变。ASCII字符只需要1个字节,拉丁字母和希腊字母需要2个字节,常用的中文字符需要3个字节,其他的一些生僻字符需要4个字节。

UTF-8的编码规则并不复杂,分为以下两种情况。

图3-8展示了“Hello算法”对应的UTF-8编码。观察发现,由于最高n位都被设置为1,因此系统可以通过读取最高位1的个数来解析出字符的长度为n。

但为什么要将其余所有字节的高2位都设置为10呢?实际上,这个10能够起到校验符的作用。假设系统从一个错误的字节开始解析文本,字节头部的10能够帮助系统快速的判断出异常。

之所以将10当作校验符,是因为在UTF-8编码规则下,不可能有字符的最高两位是10。这个结论可以用反证法来证明:假设一个字符的最高两位是10,说明该字符的长度为1,对应ASCII码。而ASCII码的最高位应该是0,与假设矛盾。

图3-8UTF-8编码示例

除了UTF-8之外,常见的编码方式还包括以下两种。

从存储空间的角度看,使用UTF-8表示英文字符非常高效,因为它仅需1个字节;使用UTF-16编码某些非英文字符(例如中文)会更加高效,因为它只需要2个字节,而UTF-8可能需要3个字节。

从兼容性的角度看,UTF-8的通用性最佳,许多工具和库都优先支持UTF-8。

对于以往的大多数编程语言,程序运行中的字符串都采用UTF-16或UTF-32这类等长的编码。在等长编码下,我们可以将字符串看作数组来处理,这种做法具有以下优点。

实际上,编程语言的字符编码方案设计是一个很有趣的话题,其涉及到许多因素。

由于以上编程语言对字符数量的低估,它们不得不采取“代理对”的方式来表示超过16位长度的Unicode字符。这是一个不得已为之的无奈之举。一方面,包含代理对的字符串中,一个字符可能占用2字节或4字节,从而丧失了等长编码的优势。另一方面,处理代理对需要增加额外代码,这增加了编程的复杂性和Debug难度。

出于以上原因,部分编程语言提出了一些不同的编码方案。

需要注意的是,以上讨论的都是字符串在编程语言中的存储方式,这和字符串如何在文件中存储或在网络中传输是两个不同的问题。在文件存储或网络传输中,我们通常会将字符串编码为UTF-8格式,以达到最优的兼容性和空间效率。

THE END
1.C++现在,我们来深入了解一些 C++ 代码以实现这些 Unicode UTF-8/UTF-16 编码转换。为实现此目标,有两个关键 Win32 API 可以使用: MultiByteToWideChar 和 its symmetric WideCharToMultiByte。可以调用前者以从 UTF-8(特定 API 术语中的“多字节”字符串)转换为 UTF-16(“宽字符”字符串);后者可用于反向转换。因为这https://msdn.microsoft.com/zh-cn/magazine/mt763237.aspx
2.C++编码最全详解c++编码类型 所属专栏:C++深入学习笔记 欢迎来到我的学习笔记! 一、什么编码? 编码:人类文字信息是有各种各样的符号组成的, 但是他们却不能直接在内存中存储。计算机内存里面只存储二进制信息0、1。无符号整型:0 ~ 255共256个收据;有符号整型:-128 ~ 127。那么内存中如何表示符号? 二、各种编码方式 2.1 ASCII编https://blog.csdn.net/lusanjiu/article/details/143085301
3.C++中文字符相关应用方法详解1.汉字编码方式的介绍 对英文字符的处理,7位ASCII码字符集中的字符即可满足使用需求,且英文字符在计算机上的输入及输出也非常简单,因此,英文字符的输入、存储、内部处理和输出都可以只用同一个编码(如ASCII码)。 而在C++中文字符处理中,汉字是一种象形文字,字数极多(现代汉字中仅常用字就有六、七千个,总字数高达https://www.51cto.com/article/182437.html
4.C/C++对Unicode编码的处理zhpacer一直都觉得C++对Unicode编码的处理比较麻烦,现就个人经验对这一方面做个总结。 Unicode编码 在领域中,Unicode(统一码、万国码、单一码、标准万国码)是业界的一种标准,它可以使电脑得以呈现世界上数十种文字的系统。Unicode是基于(Universal Character Set)的标准来发展,并且同时也以书本的形式(The Unicode Standard,目前http://blog.chinaunix.net/uid-23414687-id-2425175.html
5.一段确认中文汉字编码的代码gallop博客在遇到中文汉字乱码的时候,我们经常需要确认当前汉字的编码以及需要转换成哪种编码,以下代码能很好的协助我们进行汉字的转码: public static void printbytes(byte[] bytes){ int j = 0; String s = ""; int len = bytes.length; System.out.println ..https://www.iteye.com/blog/793940
6.运用设计模式设计MIME编码类C++MFCMIME编码的原理就是把 8 bit 的内容转换成 7 bit 的形式以能正确传输,在接收方收到之后,再将其还原成 8 bit 的内容。对邮件进行编码最初的原因是因为 Internet 上的很多网关不能正确传输8 bit 内码的字符,比如汉字等。MIME编码共有Base64、Quoted-printable、7bit、8bit和Binary等几种。 http://www.jzxx.wj.czedu.cn/html/article4420916.html
7.在C++,C#中是不是都是ASCII编码,那么为什么能输出汉字呢?不是ASCII编码,依你保存的文件格式而定,如果你的文件是UNICODE格式保存,那汉字就是UNICODE编码保存,如果你的文件是GB-2312格式,那汉字就是GB-2312编码保存 使用汉字不需要事先声明,不过需要操作系统支持,如果系统不支持汉字,比如在英文Windows上(没安装中文字体)运行,那么中文都会变成方框或乱码.https://zhidao.baidu.com/question/37834079.html
8.C++char类型和输入输出优化C语言当我们把一个字符赋值给char型变量的时候,它会去查ASCII表,找到字符对应的编号。同样,当我们使用%c输出一个字符的时候,它也会去寻找char中存储的编码对应的符号进行输出。 既然字符在C++当中都是以数字的形式存储的,那么我们就可以对它来进行加减运算。 https://m.jb51.net/article/227112.htm
9.GB2312汉字编码字符集对照表BeJSON.comGB2312汉字编码字符集对照表,GB2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时,GB 2312收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。https://www.bejson.com/document/gb2312/
10.c++C++如何从将遍历带中文的字符串呢?附带一些有关链接 unicode编码中一个汉字占几个字节? 汉字Unicode 编码范围 C++输出中文字符(转) c++utf-8编码 有用关注2收藏 回复 阅读5.5k 提及: static int num = 2; hans[num] = ch; --num; if( !num ){ // 当 num 为0时 bug? 回复2020-08-19 https://segmentfault.com/q/1010000023681498/
11.字节码:ASCII编码:单字节编码,ANSI编码:多字节编码,UNICODE编码④UTF-16编码中,一个英文字母字符或一个汉字字符存储都需要2个字节(Unicode扩展区的一些汉字存储需要4个字节)。 ⑤UTF-32编码中,世界上任何字符的存储都需要4个字节。 ANSI编码有很多种,但是都只是规定自己国家的语言,这时候出现了UNICODE编码,该编码类似于ANSI,使用多个字节表示一个字符,UNICODE编码把世界上各种主要https://cloud.tencent.com/developer/article/1065253
12.软件代码编码标准规范(c++)v1.0.doc软件代码编码标准规范(c++)-v1.0.doc,SF-研发中心-** 第1.0版 PAGE 2016-1-1发布 2016-1-1实施 成都天锐星通有限公司 第 PAGE 4 页共 NUMPAGES 43 页 天锐星通软件规范v1.0 (C++版本) 编制 日期 审核 日期 批准 日期 目的 良好的编程风格是提高程序可靠性非常重要的手段https://m.book118.com/html/2023/1118/8124072115006006.shtm