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

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

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

Solutions Collecting From Web of "为什么在与UNIX / Linux环境交互时使用UTF-8编码?"

部分原因是文件系统期望NUL('\ 0')字节终止文件名,所以UTF-16将不能正常工作。 你必须修改很多代码才能做出改变。

正如jonathan-leffler提到的,主要问题是ASCII空字符。 C传统上期望一个字符串被终止。 因此,标准的C字符串函数会阻塞任何包含相当于ASCII空字节(0x00)的字节的UTF-16字符。 虽然你当然可以使用宽字符支持进行编程,但UTF-16并不是在文件名,文本文件,环境变量中使用Unicode的合适的外部编码。

而且,UTF-16和UTF-32同时具有大端和小端的方向。 为了解决这个问题,你需要像MIME类型或Byte方向标记这样的外部元数据。 它指出,

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

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

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

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

现代的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终止的字节序列。

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

现在这个范围以外的字符,所以你不得不处理不同长度的字符,为什么会有人使用UTF-16? 如果他们今天正在设计他们的unicode支持,我怀疑微软会做出不同的决定。

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

我以为7位ASCII是好的。

严重的是,Unicode在方案上相对较新, UTF-8向后兼容ASCII,对于典型文件使用较少的空间(一半),因为每个代码点(字符)使用1到4个字节,而UTF-16使用每码点(字符)2或4个字节。

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

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