C语言学习(四)ASCII、GB2312、GBK等编码以及Unicode等字符集

(一)简介

  之前我们说过,计算机是以二机制形式来存储的,他只认识0和1两个数字。我们在屏幕上看到的文字在存储前已经被转换成了二进制,在显示时也要根据二进制找到对应的字符。

  所以,特定的字符必然对应着固定的二进制,否则在转换时会造成混乱。那么,怎样将文字与二进制对应起来呢?这就需要一套规范,计算机公司和软件开发公司都要遵守,这样的一套规范就被称为字符集(Character Set)字符编码(Character Encoding)

严格来说,字符集和字符编码不是一个概念,字符集定义了文字与二进制的对应关系,为字符分配了唯一编号。而字符编码规定了如何将文字的编号存在计算机中。我们先暂时认为他们是同一个东西,后文会做详细介绍。

  字符集为每个字符分配一个唯一的编号,类似于学生的学号。通过这些编号就能找到对应的字符。

  可以将字符集理解为一个很大表格,里面列出了所有字符和二进制的对应关系。计算机显示文字或者存储文字,就是一个查表的过程。

  在计算机发展的过程中,先后出现了几十种甚至上百种的字符集,有些还在使用,有些已经淹没在历史的长河中。接下来会介绍几种现在还在使用的字符集以及了解一些现在未使用的一些字符集。

(二)ASCII编码

拉丁字母

  在正式介绍ASCII编码之前,我们先来说说什么是拉丁字母。估计有不少读者和我一样,对拉丁字母、英文字母和汉语拼音中的字母关系不是很清楚。

  拉丁字母也叫罗马字母,它源自于希腊字母。是当今世界上使用最广泛的字母系统。最基本的拉丁字母就是我们最常见到的ABCD等26个英文字母。

拉丁字母、阿拉伯字母、斯拉夫字母(西里尔字母)被称为世界三大字母体系。

  拉丁字母原先是欧洲使用的,后来由于欧洲殖民主义,导致这套体系在全球范围内流行开来。美洲、非洲、亚洲、澳洲都没逃过西方文化的影响。中国也是,我们现在用的汉语拼音其实就是拉丁字母,是不折不扣的舶来品。

  后来很多国家对拉丁字母进行了扩展,以适应本地语言文化。最常见的扩展方式就是加上变音符号,例如汉语拼音中的ü,就是在u的基础上加上两个小点演化而来;再如,áà就是在a的上面标上音调。

  总结:

  • 基本拉丁字母就是26个英文字母
  • 扩展拉丁字母就是在26个英文字母的基础上添加变音符号、横线、斜线等,每个国家不一样

ASCII编码介绍

  计算机是美国人发明的,他们首先要考虑的是如何将二进制与英文字母(也就是拉丁文)对应起来。

  当时各个厂家和公司都有自己的做法,编码规则并不统一。这给不同计算机之间的数据交互造成了很大麻烦。但是相对来说,能够得到普遍认可的有IBM发明的EBCDIC和这边要谈的ASCII。

  我们先说ASCII(American Standard Code for Information Interchange,美国信息交换标准代码),看名字就知道,这套编码是美国人给自己设计的。他们并没有考虑欧洲那些扩展拉丁字母,更没有日文、韩文,我大中华几万个汉字更不可能被重视。

  但这也无可厚非,美国人自己发明的计算机,当然要先解决自己的问题

  ASCII 的标准版本于 1967 年第一次发布,最后一次更新则是在 1986 年,迄今为止共收录了 128 个字符,包含了基本的拉丁字母(英文字母)、阿拉伯数字(也就是 1234567890)、标点符号(,.!等)、特殊符号(@#$%^&等)以及一些具有控制功能的字符(往往不会显示出来)。

  在 ASCII 编码中,大写字母、小写字母和阿拉伯数字都是连续分布的(见下表),这给程序设计带来了很大的方便。例如要判断一个字符是否是大写字母,就可以判断该字符的 ASCII 编码值是否在 65~90 的范围内。

  EBCDIC 编码正好相反,它的英文字母不是连续排列的,中间出现了多次断续,给编程带来了一些困难。现在连 IBM 自己也不使用 EBCDIC 了,转而使用更加优秀的 ASCII。

  ASCII 编码已经成了计算机的通用标准,没有人再使用 EBCDIC 编码了,它已经消失在历史的长河中了。

ASCII码表

  标准的ASCII码表共收录了128个字符,其中包含33个控制字符(具有某些特殊功能但是无法显示的字符)和95个可显示字符。

二进制十进制十六进制字符/缩写解释
00000000000NUL (NULL)空字符
00000001101SOH (Start Of Headling)标题开始
00000010202STX(Start Of Text)
00000011303 ETX(End Of Text)正文结束
00000100404 EOT(End Of Transmission)传输结束
00000101505 ENQ(Enquiry)请求
00000110606 ACK(Acknowledge)回应/响应/收到通知
00000111707 BEL(Bell)响铃
00001000808 BS(Backspace)退格
00001001909HT (Horizontal Tab)水平制表符
00001010100ALF/NL(Line Feed/New Line)换行键
00001011110BVT (Vertical Tab)垂直制表符
00001100120CFF/NP (Form Feed/New Page)换页键
00001101130DCR (Carriage Return)回车键
00001110140ESO (Shift Out)不用切换
00001111150FSI (Shift In)启用切换
000100001610DLE (Data Link Escape)数据链路转义
000100011711DC1/XON(Device Control 1/Transmission On)设备控制1/传输开始
000100101812DC2 (Device Control 2)设备控制2
000100111913DC3/XOFF(Device Control 3/Transmission Off)设备控制3/传输中断
000101002014DC4 (Device Control 4)设备控制4
000101012115NAK (Negative Acknowledge)无响应/非正常响应/拒绝接收
000101102216SYN (Synchronous Idle)同步空闲
000101112317ETB (End of Transmission Block)传输块结束/块传输终止
000110002418CAN (Cancel)取消
000110012519EM (End of Medium)已到介质末端/介质存储已满/介质中断
00011010261ASUB (Substitute)替补/替换
00011011271BESC (Escape)逃离/取消
00011100281CFS (File Separator)文件分割符
00011101291DGS (Group Separator)组分隔符/分组符
00011110301ERS (Record Separator)记录分离符
00011111 311FUS (Unit Separator)单元分隔符
001000003220(Space)空格
001000013321!
001000103422"
001000113523#
001001003624$
001001013725%
001001103826&
001001113927
001010004028(
001010014129)
00101010422A*
00101011432B+
00101100442C,
00101101452D-
00101110462E.
00101111472F/
0011000048300
0011000149311
0011001050322
0011001151333
0011010052344
0011010153355
0011011054366
0011011155377
0011100056388
0011100157399
00111010583A:
00111011593B;
00111100603C<
00111101613D=
00111110623E>
00111111633F?
010000006440@
010000016541A
010000106642B
010000116743C
010001006844D
010001016945E
010001107046F
010001117147G
010010007248H
010010017349I
01001010744AJ
01001011754BK
01001100764CL
01001101774DM
01001110784EN
01001111794FO
010100008050P
010100018151Q
010100108252R
010100118353S
010101008454T
010101018555U
010101108656V
010101118757W
010110008858X
010110018959Y
01011010905AZ
01011011915B[
01011100925C\
01011101935D]
01011110945E^
01011111955F_
011000009660`
011000019761a
011000109862b
011000119963c
0110010010064d
0110010110165e
0110011010266f
0110011110367g
0110100010468h
0110100110569i
011010101066Aj
011010111076Bk
011011001086Cl
011011011096Dm
011011101106En
011011111116Fo
0111000011270p
0111000111371q
0111001011472r
0111001111573s
0111010011674t
0111010111775u
0111011011876v
0111011111977w
0111100012078x
0111100112179y
011110101227Az
011110111237B{
011111001247C
011111011257D}
011111101267E~
011111111277FDEL (Delete)删除

  上表列出的是标准的 ASCII 编码,它共收录了 128 个字符,用一个字节中较低的 7 个比特位(Bit)足以表示(27 = 128),所以还会空闲下一个比特位,它就被浪费了。

ASCII码和C语言

  稍微有点C语言基础的会认为C语言用的就是ASCII编码,字符在存储时会转换成对应的ASCII码值,在读取时也是根据ASCII码找到对应字符,这句话时错误的。C语言有时候使用ASCII码有时候不是,他有时候会使用接下来我们要说的GBK 编码和 Unicode 字符集。我们将在后续内容中详细介绍。

(三)GB2312编码和GBK编码,将中文存入计算机

介绍

  计算机是一种轰动全国的发明,很快就从美国传到了世界各地,并得到广泛的认可,成了一种不可替代的工具。在计算机广泛流行的过程中遇到的一个棘手的问题就是字符编码。计算机是美国人发明的,他们用的是ASCII编码,只能显示英文字符,对汉语、韩语、日语、德语等其他国家的字符无能为力。

  为了让本国公民也使用上计算机,各个国家开始也开始效仿ASCII,开发属于他们自己的字符编码。这些编码和ASCII一样,只考虑本国的语言文化,不兼容其他国家的文字。这样做的后果就是一台计算机上必须安装多个字符编码,否则就不能正确的跨国传输数据。例如,在中国编写的文本文件,在日本的电脑上就无法打开,或者打开就是一堆乱码。

下面列出了常见的字符编码:

字符编码说明
ISO/IEC 8859欧洲字符集,支持丹麦语、荷兰语、德语、意大利语、拉丁语、挪威语、葡萄牙语、西班牙语,瑞典语等,1987 年首次发布。

ASCII 编码只包含了基本的拉丁字母,没有包含欧洲很多国家所用到的一些扩展的拉丁字母,比如一些重音字母,带音标的字母等,ISO/IEC 8859 主要是在 ASCII 的基础上增加了这些衍生的拉丁字母。
Shift_Jis日语字符集,包含了全角及半角拉丁字母、平假名、片假名、符号及日语汉字,1978 年首次发布。
Big5繁体中文字符集,1984 年发布,通行于台湾、香港等地区,收录了 13053 个中文字、408个普通字符以及 33 个控制字符。
GB2312简体中文字符集,1980 年发布,共收录了 6763 个汉字,其中一级汉字 3755 个,二级汉字 3008 个;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的 682 个字符。
GBK中文字符集,是在 GB2312 的基础上进行的扩展,1995 年发布。

GB2312 收录的汉字虽然覆盖了中国大陆 99.75% 的使用频率,满足了基本的输入输出要求,但是对于人名、古汉语等方面出现的罕用字(例如朱镕基的“镕”就没有被 GB2312 收录),GB2312 并不能处理,所以后来又对 GB2312 进行了一次扩展,形成了一种新的字符集,就是 GBK。

GBK 共收录了 21886 个汉字和图形符号,包括 GB2312 中的全部汉字、非汉字符号,以及 BIG5 中的全部繁体字,还有一些生僻字。
GB18030中文字符集,是对 GBK 和 GB2312 的又一次扩展,2000 年发布。

  GB18030 |共收录 70244 个汉字,支持中国国内少数民族的文字,以及日语韩语中的汉字。

  由于ASCII先入为主,已经使用了十来年,现有很多软件和文档都是基于ASCII的,所以后来的这些字符编码都是在ASCII基础上进行扩展的,他们都兼容ASCII,以支持这些软件和文档。

  兼容ASCII的含义是,原来ASCII中已经包含的字符,在国家编码(地区编码)中的位置不变(也就是编码值不变),只是在这些字符的后面增添了新的字符。

如何存储

  标准 ASCII 编码共包含了 128 个字符,用一个字节就足以存储(实际上是用一个字节中较低的 7 位来存储),而日文、中文、韩文等包含的字符非常多,有成千上万个,一个字节肯定是不够的(一个字节最多存储 28 = 256 个字符),所以要进行扩展,用两个、三个甚至四个字节来表示。

  在制定字符编码时还要考虑内存利用率的问题。我们经常使用的字符,其编码值一般都比较小,例如字母和数字都是 ASCII 编码,其编码值不会超过 127,用一个字节存储足以,如果硬要用多个字节存储,就会浪费很多内存空间。

  为了达到「既能存储本国字符,又能节省内存」的目的,Shift-Jis、Big5、GB2312 等都采用变长的编码方式:

  • 对于原来的 ASCII 编码部分,用一个字节存储足以;
  • 对于本国的常用字符(例如汉字、标点符号等),一般用两个字节存储;
  • 对于偏远地区,或者极少使用的字符(例如藏文、蒙古文等),才使用三个甚至四个字节存储。

  总体来说,越常用的字符占用的内存越少,越罕见的字符占用的内存越多。

中文编码方案

  GB2312 --> GBK --> GB18030 是中文编码的三套方案,出现的时间从早到晚,收录的字符数目依次增加,并且向下兼容。GB2312 和 GBK 收录的字符数目较少,用 1~2个字节存储;GB18030 收录的字符最多,用1、2、4 个字节存储。

  1. 从整体上讲,GB2312 和 GBK 的编码方式一致,具体为:
  • 对于 ASCII 字符,使用一个字节存储,并且该字节的最高位是 0,这和 ASCII 编码是一致- 的,所以说 GB2312 完全兼容 ASCII。
  • 对于中国的字符,使用两个字节存储,并且规定每个字节的最高位都是 1。

  例如对于字母A,它在内存中存储为 01000001;对于汉字中,它在内存中存储为 11010110 11010000。由于单字节和双字节的最高位不一样,所以字符处理软件很容易区分一个字符到底用了几个字节。

  1. GB18030 为了容纳更多的字符,并且要区分两个字节和四个字节,所以修改了编码方案,具体为:
  • 对于 ASCII 字符,使用一个字节存储,并且该字节的最高位是 0,这和 ASCII、GB2312、GBK 编码是一致的。
  • 对于常用的中文字符,使用两个字节存储,并且规定第一个字节的最高位是 1,第二个字节的高位最多只能有一个连续的 0(第二个字节的最高位可以是 1 也可以是 0,但是当它是 0 时,次高位就不能是 0 了)。注意对比 GB2312 和 GBK,它们要求两个字节的最高位为都必须为 1。
  • 对于罕见的字符,使用四个字节存储,并且规定第一个和第三个字节的最高位是 1,第二个和第四个字节的高位必须有两个连续的 0。

  例如对于字母A,它在内存中存储为 01000001;对于汉字中,它在内存中存储为 11010110 11010000;对于藏文གྱུ,它在内存中的存储为 10000001 00110010 11101111 00110000。

  字符处理软件在处理文本时,从左往右依次扫描每个字节:

  • 如果遇到的字节的最高位是 0,那么就会断定该字符只占用了一个字节;
  • 如果遇到的字节的最高位是 1,那么该字符可能占用了两个字节,也可能占用了四个字节,不能妄下断论,所以还要继续往后扫描:
      如果第二个字节的高位有两个连续的 0,那么就会断定该字符占用了四个字节;
      如果第二个字节的高位没有连续的 0,那么就会断定该字符占用了两个字节。

  可见,当字符占用两个或者四个字节时,GB18030 编码要检测两次,处理效率比 GB2312 和 GBK 都低。

牛掰的GBK编码

  GBK 于 1995 年发布,这一年也是互联网爆发的元年,国人使用电脑越来越多,也许是 GBK 这头猪正好站在风口上,它就飞起来了,后来的中文版 Windows 都将 GBK 作为默认的中文编码方案。

  注意,这里我说 GBK 是默认的中文编码方案,并没有说 Windows 默认支持 GBK。Windows 在内核层面使用的是 Unicode 字符集(严格来说是 UTF-16 编码),但是它也给用户留出了选择的余地,如果用户不希望使用 Unicode,而是希望使用中文编码方案,那么这个时候 Windows 默认使用 GBK(当然,你可以选择使用 GB2312 或者 GB18030,不过一般没有这个必要)。

  接下来我们要讲解Unicode字符集和UTF-16编码方案。

  实际上,中文版 Windows 下的很多程序默认使用的就是 GBK 编码,例如用记事本程序创建一个 txt 文档、在 cmd 或者控制台程序(最常见的C语言程序)中显示汉字、用 Visual Studio 创建的源文件等,使用的都是 GBK 编码。

(四)Unicode字符集,将全世界的文字存储到计算机

诞生及介绍

  ASCII、GB2312、GBK、Shift_Jis、ISO/IEC 8859 等地区编码都是各个国家为了自己的语言文化开发的,不具有通用性,在一种编码下开发的软件或者编写的文档,拿到另一种编码下就会失效,必须提前使用程序转码,非常麻烦。

  人们迫切希望有一种编码能够统一世界各地的字符,计算机只要安装了这一种字编码,就能支持使用世界上所有的文字,再也不会出现乱码,再也不需要转码了,这对计算机的数据传递来说是多么的方便呀!

  就在这种呼吁下,Unicode 诞生了。Unicode 也称为统一码、万国码;看名字就知道,Unicode 希望统一所有国家的字符编码。

  Unicode 于 1994 年正式公布第一个版本,现在的规模可以容纳 100 多万个符号,是一个很大的集合。

有兴趣的读取可以转到 https://unicode-table.com/cn/ 查看 Unicode 包含的所有字符,以及各个国家的字符是如何分布的。

这个网站不太稳定,随时可能无法访问,不要问我为什么,访问不了也不要找我,没有比它更好的网站了。

  Windows、Linux、Mac OS 等常见操作系统都已经从底层(内核层面)开始支持 Unicode,大部分的网页和软件也使用 Unicode,Unicode 是大势所趋。

  不过由于历史原因,目前的计算机仍然安装了 ASCII 编码以及 GB2312、GBK、Big5、Shift-JIS 等地区编码,以支持不使用 Unicode 的软件或者文档。内核在处理字符时,一般会将地区编码先转换为 Unicode,再进行下一步处理。

Unicode字符集是如何存储的

  本节我们多次说 Unicode 是一套字符集,而不是一套字符编码,它们之间究竟有什么区别呢?

  严格来说,字符集和字符编码不是一个概念:

  • 字符集定义了字符和二进制的对应关系,为每个字符分配了唯一的编号。可以将字符集理解成一个很大的表格,它列出了所有字符和二进制的对应关系,计算机显示文字或者存储文字,就是一个查表的过程。
  • 而字符编码规定了如何将字符的编号存储到计算机中。如果使用了类似 GB2312 和 GBK 的变长存储方案(不同的字符占用的字节数不一样),那么为了区分一个字符到底使用了几个字节,就不能将字符的编号直接存储到计算机中,字符编号在存储之前必须要经过转换,在读取时还要再逆向转换一次,这套转换方案就叫做字符编码。

  有的字符集在制定时就考虑到了编码的问题,是和编码结合在一起的,例如 ASCII、GB2312、GBK、BIG5 等,所以无论称作字符集还是字符编码都无所谓,也不好区分两者的概念。而有的字符集只管制定字符的编号,至于怎么存储,那是字符编码的事情,Unicode 就是一个典型的例子,它只是定义了全球文字的唯一编号,我们还需要 UTF-8、UTF-16、UTF-32 这几种编码方案将 Unicode 存储到计算机中。

  Unicode 可以使用的编码方案有三种,分别是:

  • UTF-8:一种变长的编码方案,使用 1~6 个字节来存储
  • UTF-32:一种固定长度的编码方案,不管字符编号大小,始终使用 4 个字节来存储
  • UTF-16:介于 UTF-8 和 UTF-32 之间,使用 2 个或者 4 个字节来存储,长度既固定又可变

  UTF 是 Unicode Transformation Format 的缩写,意思是“Unicode转换格式”,后面的数字表明至少使用多少个比特位(Bit)来存储字符。

  1. UTF-8

  UTF-8 的编码规则很简单:

  • 如果只有一个字节,那么最高的比特位为 0,这样可以兼容 ASCII;
  • 如果有多个字节,那么第一个字节从最高位开始,连续有几个比特位的值为 1,就使用几个字节编码,剩下的字节均以 10 开头。

  具体的表现形式为:

  • 0xxxxxxx:单字节编码形式,这和 ASCII 编码完全一样,因此 UTF-8 是兼容 ASCII 的;
  • 110xxxxx 10xxxxxx:双字节编码形式(第一个字节有两个连续的 1)
  • 1110xxxx 10xxxxxx 10xxxxxx:三字节编码形式(第一个字节有三个连续的 1)
  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码形式(第一个字节有四个连续的 1)

  xxx 就用来存储 Unicode 中的字符编号。

  下面是一些字符的 UTF-8 编码实例(绿色部分表示本来的 Unicode 编号):

字符字母N符号æ中文⻬
Unicode 编号(二进制)010011101110011000101110 11101100
Unicode 编号(十六进制)4EE62E EC
UTF-8 编码(二进制)0100111011000011 1010011011100010 10111011 10101100
UTF-8 编码(十六进制)4EC3 A6E2 BB AC

  对于常用的字符,它的 Unicode 编号范围是 0 ~ FFFF,用 1~3 个字节足以存储,只有及其罕见,或者只有少数地区使用的字符才需要 4~6个字节存储。

  1. UTF-32

  UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 编号即可,不需要任何编码转换。浪费了空间,提高了效率。

  1. UTF-16

  UFT-16 比较奇葩,它使用 2 个或者 4 个字节来存储。

  对于 Unicode 编号范围在 0 ~ FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换,这跟 UTF-32 非常类似。

  对于 Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储,具体来说就是:将字符编号的所有比特位分成两部分,较高的一些比特位用一个值介于 D800~DBFF 之间的双字节存储,较低的一些比特位(剩下的比特位)用一个值介于 DC00~DFFF 之间的双字节存储。

  如果你不理解什么意思,请看下面的表格:

Unicode 编号范围(十六进制)具体的 Unicode 编号(二进制)UTF-16 编码编码后的字节数
0000 0000 ~ 0000 FFFFxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxx2
0001 0000—0010 FFFFyyyy yyyy yyxx xxxx xxxx110110yy yyyyyyyy 110111xx xxxxxxxx4

  位于 D800~0xDFFF 之间的 Unicode 编码是特别为四字节的 UTF-16 编码预留的,所以不应该在这个范围内指定任何字符。如果你真的去查看 Unicode 字符集,会发现这个区间内确实没有收录任何字符。

  UTF-16 要求在制定 Unicode 字符集时必须考虑到编码问题,所以真正的 Unicode 字符集也不是随意编排字符的。

对比以上三种编码方案

  首先,只有 UTF-8 兼容 ASCII,UTF-32 和 UTF-16 都不兼容 ASCII,因为它们没有单字节编码。

  1. UTF-8 使用尽量少的字节来存储一个字符,不但能够节省存储空间,而且在网络传输时也能节省流量,所以很多纯文本类型的文件(例如各种编程语言的源文件、各种日志文件和配置文件等)以及绝大多数的网页(例如百度、新浪、163等)都采用 UTF-8 编码。

  UTF-8 的缺点是效率低,不但在存储和读取时都要经过转换,而且在处理字符串时也非常麻烦。例如,要在一个 UTF-8 编码的字符串中找到第 10 个字符,就得从头开始一个一个地检索字符,这是一个很耗时的过程,因为 UTF-8 编码的字符串中每个字符占用的字节数不一样,如果不从头遍历每个字符,就不知道第 10 个字符位于第几个字节处,就无法定位。

  不过,随着算法的逐年精进,UTF-8 字符串的定位效率也越来越高了,往往不再是槽点了。

  1. UTF-32 是“以空间换效率”,正好弥补了 UTF-8 的缺点,UTF-32 的优势就是效率高:UTF-32 在存储和读取字符时不需要任何转换,在处理字符串时也能最快速地定位字符。例如,在一个 UTF-32 编码的字符串中查找第 10 个字符,很容易计算出它位于第 37 个字节处,直接获取就行,不用再逐个遍历字符了,没有比这更快的定位字符的方法了。

  但是,UTF-32 的缺点也很明显,就是太占用存储空间了,在网络传输时也会消耗很多流量。我们平常使用的字符编码值一般都比较小,用一两个字节存储足以,用四个字节简直是暴殄天物,甚至说是不能容忍的,所以 UTF-32 在应用上不如 UTF-8 和 UTF-16 广泛。

  1. UTF-16 可以看做是 UTF-8 和 UTF-32 的折中方案,它平衡了存储空间和处理效率的矛盾。对于常用的字符,用两个字节存储足以,这个时候 UTF-16 是不需要转换的,直接存储字符的编码值即可。

  Windows 内核、.NET Framework、Cocoa、Java String 内部采用的都是 UTF-16 编码。UTF-16 是幕后的功臣,我们在编辑源代码和文档时都是站在前台,所以一般感受不到,其实很多文本在后台处理时都已经转换成了 UTF-16 编码。

  不过,UNIX 家族的操作系统(Linux、Mac OS、iOS 等)内核都采用 UTF-8 编码,我们就不去争论谁好谁坏了。

宽字符和窄字符(多子节字符)

  有的编码方式采用 1~n 个字节存储,是变长的,例如 UTF-8、GB2312、GBK 等;如果一个字符使用了这种编码方式,我们就将它称为多字节字符,或者窄字符。

  有的编码方式是固定长度的,不管字符编号大小,始终采用 n 个字节存储,例如 UTF-32、UTF-16 等;如果一个字符使用了这种编码方式,我们就将它称为宽字符。

  Unicode 字符集可以使用窄字符的方式存储,也可以使用宽字符的方式存储;GB2312、GBK、Shift-JIS 等国家编码一般都使用窄字符的方式存储;ASCII 只有一个字节,无所谓窄字符和宽字符。

  说了这么多,C语言到底使用哪种字编码方式呢?其实这个问题有点复杂,我们将在后文展开讲解。

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JayerZhou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值