与UNIX / Linux环境交互时,为什么使用UTF-8编码?

时间:2020-03-06 15:02:57  来源:igfitidea点击:

我知道这是习惯,但是为什么呢?是否存在真正的技术原因,为什么任何其他方法都不是一个好主意,还是仅基于编码和向后兼容的历史?另外,不使用UTF-8而是使用其他一些编码(最值得注意的是UTF-16)会有什么危险?

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

解决方案

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

要回答"危险"问题,我们需要指定"交互"的含义。我们是要与Shell,libc还是与内核进行交互?

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

部分原因是文件系统期望NUL('\ 0')字节终止文件名,因此UTF-16不能很好地工作。我们必须修改很多代码才能进行更改。

我认为7位ASCII没问题。

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

UTF-16对于内部程序使用是更可取的,因为它的宽度更简单。它的前身UCS-2每个代码点正好是2个字节。

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

$ locale
LANG=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结尾的字节序列。

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

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

此外,UTF-16和UTF-32都具有大字节序和小字节序方向。要解决此问题,我们将需要外部元数据(例如MIME类型或者字节方向标记)。它指出,

Where UTF-8 is used transparently in
  8-bit environments, the use of a BOM
  will interfere with any protocol or
  file format that expects specific
  ASCII characters at the beginning,
  such as the use of "#!" of at the
  beginning of Unix shell scripts.

UTF-16的前身(称为UCS-2,不支持代理对)也存在相同的问题。应避免使用UCS-2.

我相信,当Microsoft开始使用两字节编码时,尚未分配大于0xffff的字符,因此使用两字节编码意味着没有人会担心字符长度不同。

现在有超出此范围的字符,因此无论如何我们都必须处理不同长度的字符,为什么有人会使用UTF-16?如果他们今天取消对unicode的支持,我怀疑Microsoft是否会做出不同的决定。