【问题标题】:Why do languages like Java distinguish between string and char while others do not? [closed]为什么像 Java 这样的语言可以区分字符串和字符,而其他语言则不区分? [关闭]
【发布时间】:2013-02-21 19:10:11
【问题描述】:

我注意到像 Java 这样的语言有一个 char 原语和一个字符串类。 Python 和 Ruby 等其他语言只有一个字符串类。这些语言使用长度为 1 的字符串来表示一个字符。

我想知道这种区别是否是由于历史原因。我了解直接影响 Java 的语言有 char 类型,但没有字符串。而是使用 char* 或 char[] 形成字符串。

但我不确定这样做是否有实际目的。我也很好奇在某些情况下一种方式是否比另一种方式更具优势。

为什么像 Java 这样的语言会区分 char 原语和字符串类,而像 Ruby 和 Python 这样的语言却没有?

肯定有某种设计方面的考虑,比如约定、效率、清晰度、易于实施等等。语言设计师真的只是从帽子里挑出一个字符表示吗?可以这么说吗?

【问题讨论】:

  • 性能。当您可以存储 int 时,为什么还要使用单独的 byte 类型?
  • 同样在 C++ 的情况下,为了与 C 兼容。
  • char 通常是一个字节(经常 翻白眼 - 是的,我在看着你,Java)。这并不总是代表可读的字符。另一方面,请注意,类形式的string 通常是可读字符的集合(不一定是)。但无论如何,提供“字符串”功能需要额外的开销。
  • 为什么脚本语言不能以这种方式提高性能?
  • @RageD 实际上,Java 设计者的决定只是随之而来的。他们说 char 用于字符而不是用于存储整数值。为此,他们引入了字节。这导致字符(您可能想要存储 unicode 数据)和从 -128 到 127 的整数值之间的结果分离。如果他们不这样做,他们将不得不引入像 wchar_t urgs 这样的东西。因此,您必须查看更多其他语言;-)

标签: java python ruby string char


【解决方案1】:

EDIT 1 增加了一些来源链接;改进了 Lisp 的历史故事;回答了为什么 Java 有原语。 EDIT 2 评论现代脚本语言,解释效率如何不再是一个问题

在过去,内存很昂贵——即使是简单的计算机也只有几千字节。您必须同意的典型服务条款将超过整个系统的 RAM。这意味着数据结构必须非常比您今天可以设计的要小得多。

计算机始于 1940 年代的英国和美国,这些工程师所需的最低字符集是西欧字母,没有任何令人兴奋的口音。 0-9、A-Z 和 a-z 为 62 个字符。添加 31 个控制字符、空格和一些标点符号,您可以将所有内容放入 7 位中。非常适合电传打字机。

现在,这 7 位可以在不同的架构上以不同的方式布局。如果您使用 IBM,您必须知道 EBCDICASCII 完全不同。

60 年代和 70 年代的语言反映了这些问题,并将字符串压缩到尽可能小的空间中:

  • Pascal:压缩的字节数组 - 固定长度且不以 null 结尾
  • C:以空值结尾的字节序列(通常被认为是一个数组,使用了疯狂的黑客思想,即数组下标只是 pointer arithmetic
  • Fortran 66:字符串?你不需要它们。将一对字符存储在一个整数中并使用READ、WRITE和FORMAT

作为这些语言的程序员,我可以说这很糟糕。特别是因为大多数商业程序需要大量的文本输入和操作。随着内存变得更便宜,程序员倾向于先编写字符串实用程序,以便能够做任何有成效的事情。

固定长度的字符串(例如 Pascal)很有效,但如果您需要扩展或收缩它们甚至是单个字符,则很麻烦。

C 的空终止方法的缺点是长度不与字符串一起存储,因此很容易覆盖缓冲区并使应用程序崩溃。此类错误仍然是计算机不安全的主要原因。有两种方法可以解决这个问题:

  • 每次写入时检查字符串长度:这意味着扫描内存,直到找到空字符。丑
  • malloc新建内存并将字符串复制到新内存中,然后free

在 80 年代,越来越多的标准库被引入来处理字符串 - 这些是由工具供应商和操作系统提供商提供的。标准化有大动作,但各方为了控制标准而争吵不休,很丑。

日益国际化也带来了另一个问题——国际字符集。首先,ASCII 扩展为 8 位为 ISO 8859-1 用于不同的欧洲语言(口音、希腊语、西里尔语),然后 Unicode 将计算机完全带到了世界的各个角落。这就带来了UTF-8UTF-16等字符编码的问题,以及如何在这些不同的方法之间进行转换。

我还应该注意到Lisp 引入了垃圾收集。这用malloc/free 解决了C 的复杂性。 Lisp 极其强大的数组和序列库可以自然地处理字符串。

第一个将这些趋势结合在一起的主要流行语言是 Java。它结合了语言的三个改进

  1. 国际化和 Unicode:一种不同的数据类型,Character 和原语 char
  2. 封装:固定长度与空终止的问题通过以下方式消除:
    1. 不可变
    2. VM 和 GC 中的巧妙优化
  3. 库:所有基本的字符串操作功能都已在该语言中标准化。

如今,有些语言的每个值都是一个对象。然而,当 Java 在 90 年代后期构思时,GC 和 JIT/Hotspot 技术远没有现在这么快(至少部分是由于 RAM 的限制,但算法也得到了改进)。 Gosling was concerned about performance 并保留原始数据类型。

另外一点:在 Java 中,有一个 Character 类是很自然的——它是许多操作和实用方法的自然归宿,例如 isWhiteSpace()isLetter(),后者在日语、韩语中有些复杂和印度语言。

Python 做了一个poor early decision 来定义一个字符为 8 位 ASCII;您可以通过首先引入另一种略有不同且不兼容的数据类型(unicode)来看到随之而来的问题,并且现在只能通过复杂的迁移到 Python 3.x 来解决。

现代语言(包括脚本语言)遵循关于字符串库外观的广泛共识,例如 Java 和 Python。

每种语言都是为特定目的而设计的,因此以不同的方式平衡相互竞争的设计问题。现代语言受益于过去 60 年来在性能和内存方面的巨大改进,因此它们更倾向于泛化、纯度和实用性,而不是 CPU 和 RAM 的效率。这对于脚本语言来说是明确的,因为脚本的性质已经做出了这个决定。因此,现代语言往往只有高级字符串类型。

TL/DR 早期的计算机在内存方面受到了可怕的限制,不得不采用最简单的实现方式。现代语言受益于 GC 识别国际化(8bit->16bit)字符并封装字符串数据类型以使字符串操作安全且容易。

【讨论】:

    【解决方案2】:

    最重要的是,这正是语言设计者决定的方式。很难比这更进一步。

    但是,关于 C 的一点是,它通常被认为是一种低级语言,因为它的语法更准确地反映了正在执行的数据和任务的性质。将字符视为字符串将是一个抽象级别,这与 C 语言不同。这会使数据在幕后的样子变得不太清楚。当你只需要一个角色时,它几乎肯定会增加开销。

    请注意,C 类型语言确实支持单字符串,因此在我看来,您确实拥有两全其美的优点。

    【讨论】:

    • 我认为这是“它应该如何”,而不是一个任意的设计决定。 char 不仅仅是一个字符表示,尽管它的名字。作为系统级语言,您需要一种可以寻址各个内存位置的类型。您可能想知道为什么可能没有与 C# 中的 char 甚至 short short int 不同的 byte 类型,但考虑到 70 年代早期计算机的功能,这将是一种奢侈的冗余。
    • 我并不是说这个决定是武断的。只是那是原因,我们可能不一定知道什么时候做出这个决定。
    • 没错,给出的答案,包括我的答案,都只能是假设和(也许是有根据的)猜测。一般来说,编写 C 是为了使编译器尽可能简单和轻量级,其设计的许多方面都表明了这一点。
    【解决方案3】:

    现在,我对此事的看法可能会以一种或另一种形式反映这里的一些答案,但我还是会说出来:

    是的,(就像其他所有人都提到的那样)C 等低级语言比 Perl、Ruby 或 Python 等脚本语言更注重优化、性能和机器级细节。现在,这种“完全控制”心态的结果是,与脚本语言相比,您通常需要担心更多的事情。

    那我想说什么?嗯,SO 的一个成员曾经给我传过“Python 之禅”,并且从该文档中仅摘录了一些核心 Python 哲学,例如“可读性很重要”、“简单胜于复杂”,以及 "There should be one-- and preferably only one --obvious way to do it. 我强调最后一次提取是有原因的。

    继续,这里是一个抽象编程语言的例子,确实有一个字符类型:SML。以我在交互模式下的两条语句为例:

    - val a = "a"
    val a = "a" : string    #interpreter type feedback
    
    - val a = #"a"
    val a = #"a" : char     #interpreter type feedback
    

    在上面的两个例子中,我有两种方法来表示一个人类可读的字符,尽管它们是根本不同的类型。尽管按照今天的标准,SML 是一种相对抽象的语言,但它的核心理念在于计算、数学表达语法和错误安全。最后一点更适用于纯函数式语言(SML 不是纯函数式)。因此,尽管抽象强调远离低级语言的可怕细节,但它仍然没有像 Python 这样的语言那样强调“可读性”和“易用性”等概念。

    事实上,脚本语言通常强调代码的快速生成,以及易于学习和使用的语法。就 Ruby 而言,松本本人甚至宣称该语言应该“使用起来很有趣”。本质上,在我最谦虚的估计中,我认为在 Python 等语言中不区分 char 和 string 数据类型的原因是简单的概念所包含的。冗长和卷积似乎是脚本语言的敌人。此外,最后一点,如果有人如此倾向于使用与 C 兼容的数据类型,那么还有适用于 Python 的 ctypes 库。

    【讨论】:

    • 唉,问题已经结束,但我仍然认为它很有用,你的回答很好。如果您不介意,您是否可以编辑您的答案以省略最后关于 C 字符串问题(空终止、memset 等)的部分?它不一定适用于 Java。
    • @Eva,我当然可以,发布后不久我也想到了这一点。很高兴它对你有用..
    【解决方案4】:

    我不确定这种区别是否是因为历史 原因(C 只有字符,字符串由 char* 或 char[] 组成)或 如果这样做有实际目的。我也很好奇 如果一种方式在某些情况下比另一种方式具有优势。

    C 中,“字符串”的概念是由结束字符\0 终止的字符数组/字符序列。否则,“字符串”就像C 中的任何其他数组一样。

    在例如C# 和其他几种语言中的字符串被视为抽象,字符串更像是一个不透明的对象。该对象包含对字符串起作用的方法,但字符串的存储方式对程序员来说是“隐藏的”。

    这是因为 C 是一种更古老的语言,并且比新语言更接近硬件。

    如何在语言中定义字符串(无论是使用单引号还是双引号)实际上只是设计该语言的人当时认为是一件好事的实现细节。

    【讨论】:

    • 脚本语言能够对字符串使用单引号,因为它们没有单独的 char 类型。我不是在问 C 语言和较新的语言之间的区别,而是在问基于 C 的语言和脚本语言之间的区别。我知道字符串对象是一种抽象。我不明白为什么脚本语言没有单独的 char 类型。
    • C 处理字符串的方式与其说是它的年龄,不如说是它的应用。您将始终需要一种可以直接处理内存、寄存器和硬件架构的系统级语言,而 C(和 C++)提供了这一点。很少有“新”语言是“系统级”的,因为 C 和 C++ 几乎涵盖了它。
    【解决方案5】:

    在 C 和 C++ 中,char 只是一个“小”整数。顾名思义,它被用于字符编码,但至少在桌面系统或任何需要支持各种语言和字母的系统上,面对 Unicode,它的用途正在减少。然而,由于这些是能够直接访问硬件的“系统级”语言,因此还必须具有能够寻址特定架构上最小的可寻址内存单元的数据类型;这就是为什么需要char

    C#区分用于字符编码的类型char(实际上是16位)和最小的可寻址单元类型byte是8位。这种清晰也许是晚到派对的优势。

    C 当然实际上根本没有字符串数据类型,它只有一个以 nul 结尾的字符数组的约定和一个使用该约定的函数库(顺便说一下,这是一个简单但低效的约定,正如 @ 解释的那样) 987654321@)。在 C++ 中,字符串类带来了真正的字符串类型的优点,并且可以避免一些低效率和危险——尽管减轻危险会增加其自身不同的性能影响)。

    【讨论】:

    • 脚本语言怎么样?
    • 他们呢?问题是关于基于 C 的语言,而 C 是一种编译语言。此外,我的观点是关于 C 语言要求成为系统级语言——在提出我的观点时,我可能没有回答你所有的问题。根据定义,脚本语言不是系统级别的——您通常不能用脚本语言(甚至是 VM 语言)编写操作系统、引导加载程序或设备驱动程序,因为它们依赖于 的运行时环境 系统。另一方面,C 具有最低的运行时要求环境要求,并且能够在没有操作系统的情况下运行“裸机”。
    • 不,问题是为什么基于 C 的语言将字符与字符串分开,而脚本语言却没有。我的问题与 C 语言本身无关。编辑我的问题,这样它就不会说 C 来结束这种混乱。
    • 好的,那么从我的回答中,您可能会得出结论,非系统级语言不需要处理基本机器类型,而是需要处理抽象类型。
    猜你喜欢
    • 1970-01-01
    • 2010-10-17
    • 2011-03-03
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    相关资源
    最近更新 更多