类型推断的常量只能是标量值 - 即整数、双精度值等。对于这些类型的常量,编译器确实会在表达式中遇到常量时将常量的符号替换为常量的值。
另一方面,类型化的常量可以是结构化值——数组和记录。这些家伙需要在可执行文件中实际存储——即他们需要为他们分配存储空间,这样,当操作系统加载可执行文件时,类型化常量的值物理上包含在内存中的某个位置。
为了解释为什么在历史上早期 Delphi 及其前身 Turbo Pascal 中的类型化常量是可写的(因此本质上是初始化的全局变量),我们需要回到 DOS 时代。
DOS 以 x86 术语在实模式下运行。这意味着程序可以直接访问物理内存,而无需任何MMU进行虚拟物理映射。当程序可以直接访问内存时,没有内存保护生效。换句话说,如果任何给定地址有内存,它在实模式下都是可读和可写的。
因此,在用于 DOS 的 Turbo Pascal 程序中,具有类型化常量,其值在运行时分配到内存中的某个地址,该类型化常量将是可写的。没有硬件 MMU 妨碍并阻止程序对其进行写入。同样,因为 Pascal 没有 C++ 所具有的“常量”概念,所以类型系统中没有什么可以阻止您。很多人利用了这一点,因为当时 Turbo Pascal 和 Delphi 还没有将全局变量初始化为特性。
转到 Windows,在内存地址和物理地址之间有一层:内存管理单元。该芯片获取您尝试访问的内存地址的页索引(移位掩码),并在其页表中查找该页的属性。这些属性包括可读、可写,对于现代 x86 芯片,还有不可执行标志。借助此支持,可以使用属性标记 .EXE 或 .DLL 的部分,以便当 Windows 加载程序将可执行映像加载到内存中时,它会为映射到这些部分中的磁盘页面的内存页面分配适当的页面属性。
当 32 位 Windows 版本的 Delphi 编译器问世时,将类似 const 的东西变成真正的 const是有意义的,因为操作系统也有这个特性。