我将一些Delphi代码从一个项目复制到另一个项目,并发现它不能在新项目中编译,尽管它在旧项目中编译.代码看起来像这样:
procedure TForm1.CalculateGP(..) const Price : money = 0; begin ... Price := 1.0; ... end;
所以在新项目中,Delphi抱怨"左侧无法分配" - 可以理解!但是这段代码在旧项目中编译.所以我的问题是,为什么?是否有编译器开关允许重新分配consts?这怎么样?我认为在编译时它们的值被替换了?
您需要打开可分配的类型常量.项目 - >选项 - >编译器 - >可分配的类型常量
你也可以添加{$J+}
或者更新{$WRITEABLECONST ON}
pas文件,这可能更好,因为即使你将文件移动到另一个项目它也会工作.
类型推断的常量只能是标量值 - 即整数,双精度等等.对于这些常量,编译器确实会在常量的符号表达式中使用常量的值替换常量的符号.
另一方面,键入的常量可以是结构化值 - 数组和记录.这些人需要在可执行文件中实际存储 - 即他们需要为他们分配存储,这样当操作系统加载可执行文件时,类型化常量的值实际上包含在内存中的某个位置.
为了解释为什么历史上早期Delphi及其前身Turbo Pascal中的类型常量是可写的(因此基本上是初始化的全局变量),我们需要回到DOS的时代.
DOS以实时模式运行,x86术语.这意味着程序可以直接访问物理内存,而无需任何MMU进行虚拟物理映射.当程序可以直接访问内存时,没有内存保护功能生效.换句话说,如果在任何给定地址处存在存储器,则它在实模式下都是可读写的.
因此,在具有类型常量的DOS的Turbo Pascal程序中,其值在运行时在内存中的地址处分配,该类型常量将是可写的.没有硬件MMU阻碍并阻止程序写入它.同样,因为Pascal没有C++所具有的'const'ness概念,所以类型系统中没有任何东西可以阻止你.很多人都利用了这一点,因为Turbo Pascal和Delphi当时没有将全局变量初始化为一个特征.
继续使用Windows,内存地址和物理地址之间有一层:内存管理单元.该芯片获取您尝试访问的内存地址的页面索引(移位掩码),并在其页面表中查找此页面的属性.这些属性包括可读,可写和现代x86芯片,非可执行标志.通过此支持,可以使用以下属性标记.EXE或.DLL的各个部分:当Windows加载程序将可执行映像加载到内存中时,它会为映射到这些部分中的磁盘页的内存页分配适当的页面属性.
当32位Windows版本的Delphi编译器出现时,因此操作系统也具有此功能,因此使const类似的东西变得非常有意义.
原因:因为在Delphi的早期版本中,默认情况下可以分配类型常量以保持与旧版本的兼容性,在旧版本中它们始终是可写的(Delphi 1直到早期的Pascal).
现在已经更改了默认值以使常量真正保持不变...
编译器开关:{$ J +}或{$ J-} {$ WRITEABLECONST ON}或{$ WRITEABLECONST OFF}
或者在编译器的项目选项中:检查可分配的类型化常量
工作原理:如果编译器可以在编译时计算该值,它会在代码中的任何位置用const值替换const,否则它会保存一个指向保存该值的内存区域的指针,该值可以写入或不可写.
见3.