一个字固定等于两个字节么,Unicode编码中一个字符固定是2个字节吗?UTF-16和UTF-32与字长有何关系?

题图来自Unsplash,基于CC0协议
导读
字符在计算机世界里的旅程是一条充满曲折的路。许多人认为一个"字"固定等于两个字节,但实际上这只是一个常见误解,具体何时、何地、为何、何解,还得看具体的语境与技术方案。我们来看一下这些复杂的背景:
关于字符存储的基本概念,首先要区分"字符"和"字节"这两个概念。计算机处理和存储的基本单位是字节,一个字节由8位构成,是数据存储的最小单位。字符编码则规定了如何将现实中的文字符号转换为一连串的二进制位,而这些二进制位再按照字节组织,被存储或传输。
一个字节能存储不同的信息,从0到255一共256种可能。这256个数值可以代表不同的东西,例如ASCII字符、数字、控制码或更复杂编码的一部分。
字符在计算机中不总是固定等于两个字节。这取决于你采用的字符编码标准(Character Encoding Standard)。
以下是不同字符编码下字占字节数的对比:
| 字符/编码类型 | 每个字符的文字(字) | 概述和例子 |
|---|---|---|
| ASCII | 英文字符、数字和符号用1字节;与其他语言字符基本不兼容 | 美国信息交换标准代码,一种使用7位或8位二进制表示的字符编码。英文字符、数字和一些标点符号可以通过一个字节(8位)来表示。在很多老旧系统或特定场合,为了兼容,8位ASCII有时也被称为一个"字节",但它本质上代表的是一个字符。然而,其单字节编码范围(0-127,扩展到0-255)有限,无法表示除了基本拉丁字母之外的其他语言文字。所以,系统认为一个"字"等于两个字节的结论,ASCII环境下不适用,且ASCII主要用于英语场景。 |
| GB2312 和 GBK | 汉字通常用2字节表示,但编码可变(不一定严格固定) | GB2312是中国的国家标准,采用双字节编码(每个汉字用两个字节表示,一个"字"基本等于两个字节)。这是为了解决ASCII字节半浪费(大部分容量未用)和中文字符数量庞大问题。后续演进的GBK扩展了字符集,增加了更多汉字和其他语言的字符,但通常仍采用双字节编码,每个"汉字"依然占两个字节。 |
| UTF-8 | 可变字节数:ASCII字符用1字节;大部分汉字和其他Unicode字符用3字节 | RFC 2279定义,一种兼容ASCII的Unicode编码方案。其核心优势在于向前兼容ASCII:英文字符仍然使用1个字节,与ASCII一致,这保证了与大量现有系统的兼容性。占用超过1个字节的Unicode字符(如大部分汉字),则使用1-4个字节来表示,具体字节数取决于字符的Unicode代码点值。"字"在这里没有固定的字节数,汉字通常不占2字节。 |
| Unicode整体而言 | 不是,Unicode只是一个框架,其具体实现编码标准(UTF-8, UTF-16, UTF-32)决定了字节数 | Unicode本身是给每个字符分配一个唯一的数字编号(代码点),就像给世界上所有文字字符分配了身份证号一样。实现这些数字如何在计算机中存储和传输,有多种标准: |
- UTF-16: 使用2个或4个字节。它试图在存储空间和处理效率上取得平衡。对于代码点范围在U+0000到U+FFFF的字符(ASCII+大部分常用汉字),只需要2个字节。但对于更远古的语言变体或同音字符(U+10000到U+10FFFF),需要额外的"代理对"表示,因此可能用到4个字节。它的字节长度是可变的。
- UTF-32: 使用固定4个字节。它最简单,直接,便于算术运算,但需要4个字节来表示任何一个字符,这是最"大度"但也最费空间。
- UTF-8: 现实中使用最广的技术方案,支持用1、2、3或4个字节表示字符,确保了向ASCII兼容,不易出现乱码。对于汉字字符(U+4E00 到 U+9FFF 和 U+F900-U+FFFF),通常是3个字节(也少部分是2个字节,但现在少见)。 早期Windows系统为什么常认为一个字等于两个字节(byte)? | | 历史原因和系统设计 | 这主要源于两个关键技术点的耦合:CPU架构 和 当时主流字符编码UCS-2/UTF-16。
- CPU架构: Windows早期主要运行在Intel x86架构上,其CPU字长在16位时代为16位(一次能处理16位数据),后来虽然发展到32位(处理32位),但很多底层设计仍有遗留。操作系统结构、系统调用接口等有时会与16位字全相关联。
- 字符编码选择: Windows在引入Unicode(内部称为UCS-2)之前和初期,大量使用了基于ANSI的多字节编码,如GB2312、Shift-JIS、Big5等。这些编码普遍采用固定两个字节来表示大部分汉字和本地化字符。
- 最初统一Unicode时,Windows 95/NT引入了 UCS-2作为其内部Unicode实现,它是UTF-16的一个早期形式,使用固定两个字节来编码字符(通过代理对机制理论上支持更多字符,但大部分常用字符确实只用2字节)。这使得许多Windows API和部分系统组件在思想深处仍偏向认为"字符大约需要16位,即两个字节"。早期硬件(如某些显卡驱动程序)也可能与16位机制相关联。| | 现代编程语言中字符存储单位是怎么回事? | | 不固定,常见于使用Unicode/UTF-16的字符(char)类型。 | | 基本概念:字符是抽象概念,字节是物理单位。**
- 固定宽度字符集(如UTF-8): 每个字符占用固定数量的字节(如1、2、3、4)。
- 可变宽度字符集(如UTF-8): 每个字符占用字节数可变。 | 在现代编程语言中:
- 语言特性:
- C/C++/Go/Rust/jni等: 常常将char类型定义为简单的一个字节(unsigned char)。程序员需要自己关心字符编码(如UTF-8)、字符的组装拆分和内存管理。
- C#/Java: 将char类型定义为固定两个字节(在C#中是UTF-16,Java也是UTF-16)来表示内存中的Unicode字符。这对于中等常用字符来说效率不错,但Unicode字符表现在Unicode 2.0到14.0期间,几乎所有字符都是2个16位代码单元/字节。但支持了更多字符类别后,超出16位范围的字符就需要"代理对"。Java更明确地将自己的Character类定义在UTF-16编码上。
- Python/JavaScript/Python 在不同模式下: Python 3使用Unicode(str类型),存储默认采用UTF-8编码来处理字符串。在JavaScript中,String是一种抽象类型,其内部使用UTF-16编码(称为UTF-16be,因为JavaScript运行在doubleword-aligned平台上,通常返回的是顺字节序)来表示,每个字符占用Unicode代码单元,这通常对应两个16位单元/4个字节,但低码点字符或某些特殊情况可能更少或更多。
- 总结: 字节是计算机存储的基本单元,直接与硬件紧密相关。字符则是一个抽象概念,代表现实中的笔画、音调等。连接两者的,是字符编码方案。字符编码方式(如ASCII、GB2312、UTF-8、UTF-16、UTF-32)决定了一个字符在计算机中占用多少个字节。很多时候,看似一个"字"等于两个字节,往往是在特定的历史时期、科技选择(如早期的UCS-2/UTF-16配合16位时代CPU架构、或现代常用场景如GB2312)下的具体实现,而非字符本身的固有属性。现代环境下,尤其是处理全球多种语言时,采用可变变长编码(如UTF-8)解决了兼容性问题,已成为主流趋势,但这并不意味着"2字节=一个字符"这个简单等式永恒不变。
© 版权声明
本文由盾科技原创,版权归 盾科技所有,未经允许禁止任何形式的转载。转载请联系candieraddenipc92@gmail.com