为什么我们必须在 UTF-16 和 UTF-32 编码的情况下指定 BOM



我不太了解UTF编码和BOM背后的原理。

如果计算机已经知道如何将多字节数据类型(例如,大小为 4 字节的整数)组合成一个变量,那么使用 UTF-16 和 UTF-32 格式的 BOM 有什么意义?那么为什么我们需要为这些编码明确指定它呢?

为什么我们不需要为 UTF-8 指定它?Unicode 标准说它是"面向字节的",但即便如此,我们还需要知道它是否是编码码位的第一个字节。还是在每个字符的第一个/最后一个位中指定?

UTF-16 是两个字节宽,让我们将该字节称为B0|B1。假设我们有字母"a",这在逻辑上是数字0x0061。不幸的是,不同的计算机体系结构以不同的方式将此数字存储在内存中,在x86平台上,不太有效的字节首先存储(在较低的内存地址),因此"a"将存储为00|61。在PowerPC上,这将存储为61|00,因此这两种架构被称为小端序和大端序。

为了加快字符串处理速度,库通常按本机顺序(大结尾或小端序)存储两个字节字符。交换字节太昂贵了。

现在想象一下,PowerPC 上的某人将字符串写入文件,库将写入字节00|61,现在 x86 上的某人想要读取此字节,但这是否意味着00|6161|00?我们可以在字符串的开头放置特殊的序列,这样任何人都可以知道用于保存字符串的字节顺序,并正确处理它(在字节序之间转换字符串是一项昂贵的操作,但大多数时候 x86 字符串将在 x86 arch 上读取,PowerPC 字符串将在 PowerPC 机器上读取)

对于 UTF-8,

这是不同的情况,UTF-8 使用单顺序并将字符长度编码为第一个字符的第一个位的模式。UTF-8编码在维基百科上有很好的描述。一般来说,它旨在避免字节序的问题

不同的体系结构可以以不同的方式编码事物。一个系统可能将0x12345678写为0x12 0x34 0x56 0x78,另一个系统可能将其写为0x78 0x56 0x34 0x12。重要的是要有一种方法来理解源系统是如何编写内容的。字节是读取或写入的最小单位,因此如果格式是逐字节写入的,则没有问题,就像没有系统在读取另一个系统写入的 ASCII 文件时遇到问题一样。

UTF-16 BOM 表U+FEFF将写入0xFE 0xFF或0xFF 0xFE,具体取决于系统。知道这些字节的写入顺序会告诉读者字节在文件其余部分的顺序。UTF-32 使用相同的 BOM 字符,填充 16 个零位,但其用法相同。

另一方面,UTF-8 被设计为一次读取一个字节。因此,顺序在所有系统上都是相同的,即使在处理多字节字符时也是如此。

UTF-16 和 UTF-32 编码不指定字节顺序。在 8 位字节流中,码位 U+FEFF 可以用 UTF-16 编码为字节 FE、FF(大端序)或 FF、FE(小端序)。流编写器显然无法知道流的最终位置(文件,网络套接字,本地程序?),因此您在开头放置BOM以帮助读取器确定编码和字节顺序变体。

UTF-8 没有这种歧义,因为它从一开始就是面向字节的编码。用 UTF-8 编码此代码点的唯一方法是按此精确顺序使用字节 EF、BB、BF。(方便的是,序列化的第一个字节中的高位还显示了序列将占用多少字节。

最新更新