【发布时间】:2012-03-10 08:57:39
【问题描述】:
为什么 Java 中的字符存储空间是 C 中字符的两倍?
【问题讨论】:
-
Java 的功能是 C++ 的两倍,而力量必须来自某个地方......
-
@KerrekSB 但它可以有 256 倍的字符。 ;)
为什么 Java 中的字符存储空间是 C 中字符的两倍?
【问题讨论】:
Java 是一种现代语言,出现在Unicode 时代早期(90 年代初),因此它默认支持 Unicode 作为一等公民像许多新的当代语言(如 Python、Visual Basic 或 JavaScript...)、操作系统(Windows、Symbian、BREW...)和框架/接口/规范...(如 Qt、NTFS ,朱丽叶)。在设计这些代码时,Unicode 是一个固定 16 位字符集,以UCS-2 编码,因此对他们使用 16 位字符值是有意义的
相比之下,C 是一种“古老”的语言,它比 Java 早了几十年发明,当时 Unicode 还远未出现。那是 7 位 ASCII 和 8 位 EBCDIC 的时代,因此 C 使用 8 位 char1 作为 足以让 char 变量包含所有基本字符 .来到 Unicode 时代,为了避免破坏旧代码,他们决定在 C90 中引入不同的字符类型,即wchar_t。再次,这是 90 年代 Unicode 开始它的生命。在任何情况下,char 必须继续使用旧大小,因为即使使用更宽的字符,您仍然需要访问单个字节(Java 有一个单独的 byte 类型用于此目的)
当然,后来 Unicode 联盟很快意识到 16 位是不够的,必须以某种方式修复它。他们通过将 UCS-2 更改为 UTF-16 来扩大代码点范围,以避免破坏使用 wide char 并将 Unicode 作为 21 位字符集(实际上高达 U+10FFFF instead of U+1FFFFF because of UTF-16)的旧代码。不幸的是,为时已晚,使用 16 位字符的旧实现卡住了
后来我们看到了UTF-8的出现,它被证明远优于UTF-16,因为它独立于字节序,通常占用更少的空间,最重要的是它不需要更改标准C字符串功能。大多数收到char* 的用户函数将在没有特殊Unicode 支持的情况下继续工作
Unix 系统很幸运,因为它们后来在引入 UTF-8 时迁移到 Unicode,因此继续使用 8 位字符。 OTOH 默认情况下,所有现代 Win32 API 都在 16 位 wchar_t 上工作,因为 Windows 也是 Unicode 的早期采用者。因此,.NET 框架和 C# 也采用相同的方式,将 char 作为 16 位类型。
谈到wchar_t,它是如此不可移植,以至于C 和C++ 标准都需要在其2011 年的修订版中引入新的字符类型char16_t and char32_t
C 和 C++ 都在各自标准的 2011 年修订版中引入了固定大小的字符类型
char16_t和char32_t,以提供 16 位和 32 位 Unicode 转换格式的明确表示,让 wchar_t 实现定义https://en.wikipedia.org/wiki/Wide_character#Programming_specifics
也就是说,大多数实现都在努力改善宽字符串的情况。 Java 在 Java 6 中试验了compressed string,并在 Java 9 中引入了compact strings。与 3.3 之前的 Python 中的wchar_t* 相比,Python 正在向more flexible internal representation 移动。 Firefox 和 Chrome 对简单字符串有单独的内部 8 位字符表示。 .NET framework 也有关于此的讨论。而最近 Windows 正在逐步引入UTF-8 support for the old ANSI APIs
1 严格来说,C 中的char 只需要至少 8 位。见What platforms have something other than 8-bit char?
【讨论】:
Java char 是 UTF-16 编码的 Unicode 代码点,而 C 在大多数情况下使用 ASCII 编码。
【讨论】:
由于Java使用Unicode,C一般默认使用ASCII。
Unicode 编码有多种风格,但 Java 使用 UTF-16,每个字符使用一个或两个 16 位 代码单元。 ASCII 总是每个字符使用一个字节。
【讨论】:
Java 中的字符是 16 位的,而 C 中的字符是 8 位的。
一个更普遍的问题是为什么会这样?
要找出为什么您需要查看历史并就该主题得出结论/意见。
当 C 在美国开发时,ASCII 是相当标准的,你只需要 7 位,但使用 8 位你也可以处理一些非 ASCII 字符。这似乎绰绰有余。许多基于文本的协议,如 SMTP(电子邮件)、XML 和 FIX,仍然只使用 ASCII 字符。电子邮件和 XML 编码非 ASCII 字符。二进制文件、套接字和流仍然只有 8 位字节。
顺便说一句:C 可以支持更宽的字符,但这不是普通的char
在开发 Java 时,16 位似乎足以支持大多数语言。从那时起,unicode 已扩展到 65535 以上的字符,Java 不得不添加对 UTF-16 字符的代码点的支持,并且可以是一个或两个 16 位字符。
因此,将byte 设置为一个字节,将char 设置为一个无符号的 16 位值在当时是有意义的。
顺便说一句:如果您的 JVM 支持 -XX:+UseCompressedStrings,它可以使用字节而不是字符来表示仅使用 8 位字符的字符串。
【讨论】:
Java 2 平台在 char 数组中使用 UTF-16 表示,并且 在 String 和 StringBuffer 类中。
【讨论】: