12

我知道这是习惯,但为什么呢?是否有真正的技术原因为什么任何其他方式都是一个非常糟糕的主意,或者它只是基于编码和向后兼容性的历史?此外,不使用UTF-8,而是使用其他编码(最值得注意的是,UTF-16)有什么危险?

编辑:通过交互,我主要是指shelland libc

4

8 回答 8

16

部分是因为文件系统需要 NUL ('\0') 字节来终止文件名,所以 UTF-16 不能很好地工作。您必须修改大量代码才能进行更改。

于 2008-10-02T20:33:44.207 回答
9

正如 jonathan-leffler 提到的,主要问题是 ASCII 空字符。C 传统上期望字符串以空值结尾。因此,标准 C 字符串函数将阻塞包含等效于 ASCII null (0x00) 的字节的任何 UTF-16 字符。虽然您当然可以使用广泛的字符支持进行编程,但 UTF-16 不是文件名、文本文件、环境变量中 Unicode 的合适外部编码。

此外,UTF-16 和 UTF-32 具有大端和小端方向。为了解决这个问题,您需要外部元数据,例如 MIME 类型或Byte Orientation Mark。它指出,

在 8 位环境中透明地使用 UTF-8 的情况下,使用 BOM 会干扰任何需要以特定 ASCII 字符开头的协议或文件格式,例如使用“#!” 在 Unix shell 脚本的开头。

UTF-16 的前身,称为 UCS-2,不支持代理对,也有同样的问题。应避免使用 UCS-2。

于 2008-10-02T22:40:39.223 回答
2

我相信这主要是 UTF8 与 ASCII 提供的向后兼容性。

要回答“危险”问题,您需要指定“交互”的含义。您的意思是与 shell、libc 或内核交互吗?

于 2008-10-02T20:32:22.400 回答
2

现代 Unix 使用 UTF-8,但这并不总是正确的。在只有几年历史的 RHEL2 上,默认值为

$ 语言环境
朗=C
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=
C/POSIX 语言环境应为 7 位 ASCII 兼容编码。

然而,正如 Jonathan Leffler 所说,任何允许在字符序列中包含 NUL 字节的编码在 Unix 上都是不可行的,因为系统 API 是区域设置无关的;字符串都被假定为以 \0 结尾的字节序列。

于 2008-10-02T20:50:21.453 回答
1

我相信当微软开始使用两字节编码时,0xffff 以上的字符还没有被分配,所以使用两字节编码意味着没有人需要担心字符长度不同。

既然有超出此范围的字符,那么无论如何您都必须处理不同长度的字符,为什么有人会使用 UTF-16?我怀疑如果微软今天设计他们的 unicode 支持,他们会做出不同的决定。

于 2008-10-06T13:13:35.480 回答
0

是的,这是出于兼容性原因。UTF-8 可以向后兼容 ASCII。Linux/Unix 是基于 ASCII 的,所以它才有意义。

于 2008-10-02T20:33:23.583 回答
0

我认为 7 位 ASCII 很好。

严肃地说,Unicode 在事物方案中相对较新,UTF-8向后兼容 ASCII,并且对于典型文件使用更少的空间(一半),因为它每个代码点(字符)使用 1 到 4 个字节,而UTF-16使用每个代码点(字符)2 或 4 个字节。

由于更简单的宽度,UTF-16 更适合内部程序使用。它的前身 UCS-2 恰好是每个代码点的 2 个字节。

于 2008-10-02T20:39:37.563 回答
0

我认为这是因为期望 ASCII 输入的程序将无法处理 UTF-16 等编码。对于大多数字符(在 0-255 范围内),这些程序会将高字节视为 NUL / 0 字符,它在许多语言和系统中用于标记字符串的结尾。这在 UTF-8 中不会发生,它旨在避免嵌入 NUL 并且与字节顺序无关。

于 2008-10-02T20:56:54.823 回答