原文出自这里
开放式系统社区(OpenSystem community)目前是时间该决定如何实现64位架构的支持了(译注:本文写于1998年前后)。本文中从技术角度列出的种种证据表明,相对于其他编程模型(ILP64和LLP64),LP64是更好的选择。主要的评估指标包括可移植性、32位环境的兼容性、标准的一致性、性能影响以及移植的代价;在我们针对这些指标分析完各种数据模型后,你会发现LP64毫无疑问就是我们的最佳选择。
对于更大的Flat地址空间需求是使用64位系统的关键原因。目前在计算机界已经有很多关于32位地址局限性的讨论。以byte为单位的32位地址空间最多可以寻址4GB的内存。磁盘存储器的单位密度正在以每年70%的速度增长,高达4G的驱动器很快就将被应用于高密度存储器中。(本文写于97~98年左右)。内存价格还没有显著下降,不过16MB芯片已经十分稳定,64MB芯片也正在开发之中。CPU的运行功耗正在以每18个月增加50%的速度持续上升,以便保证有足够的功耗可以处理更大量的数据。鉴于以上各个硬件技术的发展,以及当今系统中越来越大的数据量、虚拟模型还有新的数据格式(比如全动态视频图像)都需要更大的地址空间结构。
目前大多数的芯片架构已开始提供大于4GB地址空间的直接寻址。由于这些新的芯片和系统已经开始进入市场,我们现在有一个机会可以制定一个统一的编程模型,从而避免了不必要的风险。显然这个模型也应该加入现有的开放式系统规范中。此外,如果各种编程模型可以在一些细节上达成一致,那么应用程序开发者可以使用单一的编程环境应对不同的操作系统供应商,减少后期维护的成本。
C语言缺少一种增加新的基本数据类型的机制。C程序开发人员为了提供64位寻址和标量运算的能力,需要改变现有的数据类型的定义或映射或添加新的数据类型。
如下表所示,由三种基本的数据模型可供选择,LP64, ILP64 和LLP64。表中标出了各种基本数据类型所占用的位宽。LP64(也称为4/8/8)使用64位数据表示long和指针类型,ILP64(也称为8/8/8)使用64位数据表示int、long、和指针,LLP(也称为4/4/8)将一种新的long long类型和指针定义为64位长度。目前大多数的32位系统使用ILP32(就是说,int、long、和指针都是32位长度)。在Windows3.1上使用的C语言程序都是使用的Win-16API,这是基于LP32的(int是16位,而long和指针是32位)。在Apple Macintosh上的C也是使用LP32。
Datatype | LP64 |
ILP64 |
LLP64 |
ILP32 |
LP32 |
char | 8 | 8 | 8 | 8 | 8 |
short | 16 | 16 | 16 | 16 | 16 |
_int32 | 32 | ||||
int | 32 | 64 | 32 | 32 | 16 |
long | 64 | 64 | 32 | 32 | 32 |
long long | 64 | ||||
pointer | 64 | 64 | 64 | 32 | 32 |
C语言标准规定了一套各种数据类型之间的关系,但故意没有定义具体长度。如果不考虑非标准类型的话,三种64位指针模型都可以兼容现有的规则。
C语言基本数据类型的位宽变化或多或少都会影响程序。在这里可能会出现两个基本问题:(1)在64位系统上定义的数据类型迁移到16位或32位的系统上后,数据位宽可能发生变化(译注:进而导致数据丢失或错误),还有(2)假定的(不是那些在C标准中指定的,而是由开发者定义在代码片断中的)基本数据类型之间的既有关系可能不再有效。依赖于这些关系的程序经常停止正常工作。(译注:比如sizeof(int) == sizeof(int *)在32位系统中是成立的,但是在64位系统中可能是不成立的)。
LLP64保留了32位数据类型中int和long的定义(int和long都为32位长度)。除了指针对象以外,其他数据类型都同32位系统完全一样。为了支持64位的标量数据,LLP64定义了一种新的不可移植的数据类型long long,或者叫做__int64。LLP64实际上是一个32位的模型加上了64位地址。大多数程序运行时C语言基本数据类型变化产生的问题经常是假设了指针和int型数据是等长的(译注:即上文中的基本问题2)。为了解决这个问题,int和long类型被非标准的long long类型取代。这个方法完美的解决了上文中提到的第一个基本问题(译注:即代码迁移中数据长度不一致导致的数据丢失或错误),但是它引入了一个新的数据类型。
基于LLP64的操作系统必须修改许多系统程序编程接口(API)的数据类型定义,或引入一组新的64位的接口。然而大多数这些接口已经在所有UNIX操作系统上稳定使用了近25年。因此,LLP64需要在现有的规范上增加和修改,以便保证这些使用旧的接口的地方能更容易迁移到64位宽度.
ILP64尝试将int, long和指针使用相同的宽度(同ILP32保持一致)。这样将指针赋值给int或long变量就不会有数据丢失。另一方面这个模型要么得损害了数据的可移植性,要么必须依赖于新增加的32位数据类型如int32或__int32。这是一个潜在的冲突,尤其是违背了C语言的精神,避免在基本数据类型中嵌入数据大小描述。这样必须保证固定数据长度和对齐的代码就不得不使用非标准数据类型,并且不具备可移植性。
目前世界上主要由32位计算机占主导地位,在可以预见的未来可能会出现这样一种情况,这些计算机上会运行16位或32位程序,或者两种都混合使用。同时64位CPU将会运行32位或64位代码,或者混合同时使用(甚至也许还包括一些16位代码)。64位应用程序和系统必须将这些应用环境顺利地融入到一起。软件行业面临的主要问题是如何在64和32位系统之间交互数据(有时候可能是在同一个系统中完成32位程序数据和64位程序数据的交互),当然还有同时在两个环境中维护软件的成本。这种交互主要出现在大型软件套件中(例如数据库系统),这些软件可能需要将大多数的程序作为32位二进制文件分发到各个现有的数据终端,但是对于一些关键程序比如服务器进程,则希望使用64位的程序。ILP64意味着频繁更改源代码,并且需要使用非标准的数据类型来实现交互,以及现有数据之间的二进制兼容性。
LP64选择了折中的方式。它使用8位,16位和32位标量类型(char,short和int)来保证兼容32位系统中数据大小和对齐,使用64位的long型来支持完整的运算能力,以及64位的指针运算。程序中要将指针地址强制转换成标量时必须使用long而不是int型。在64位系统下能正常工作的代码在32为系统中不用做任何修改就能正常编译和运行。这些数据类型是天然的,每个标量类型都比先前的类型要长。
作为一个语言设计问题,使用long类型的目的主要是考虑到有时候需要一个比int型更长的整型数据。事实上,int和long代表不同宽度的数据类型是非常自然并且符合常识的,在PC世界的标准中,int是16位,long为32位。