Delphi:所有常量都是常量,但有些常量比其他常量更常量?

问题描述 投票:0回答:7

考虑一下:

const 
  clHotlight: TColor = $00FF9933;
  clLink = clHotLight; //alias of clHotlight

[错误] file.pas:需要常量表达式

有效的替代措辞:

const 
  clHotlight = TColor($00FF9933);
  clLink = clHotLight; //alias of clHotlight

请解释一下。


然后考虑一下:

const 
  AdministratorGUID: TGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
  SuperuserGUID = AdministratorGUID; //alias of AdministratorGUID

[错误] file.pas:需要常量表达式

以及修复。

编辑:在声明之前添加了关键字

const
;有人不相信他们是常量。

delphi constants compiler-errors delphi-5 compile-time-constant
7个回答
23
投票

clHotlight: TColor = $00FF9933;
不是常量,而是类型常量(=静态变量),即编译器在内存中为 TColor 保留一个槽,该槽将在运行时最初保存值
$00FF9933

因为该值可以稍后更改(使用可分配常量选项打开),所以它不是真正的常量,并且不能被编译器接受
clLink = clHotLight;

clHotlight = TColor($00FF9933);
clHotlight = $00FF9933;

严格相同 它是一个真正的常量,编译器将用其值
clHotlight
替换
$00FF9933
,无论它出现在代码中。还有
clLink

阅读这个SO问题(在Delphi 7中,为什么我可以给const赋值?)以及那里所有好的答案...

编辑:关于 TGUID...
问题是写

AdministratorGUID: TGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
不合适。
它使用一些编译器魔法在幕后调用
StringToGUID
,从而可以方便地将GUID表示为字符串,而它们本质上不是字符串。它们是记录。

所以,尝试

AdministratorGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
是行不通的。那不是 GUID...

解决方法是使用 absolute 指令让类型常量

变量指向同一内存区域:

const
   AdministratorGUID: TGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
var
   SuperuserGUID: TGUID absolute AdministratorGUID; //alias of AdministratorGUID
   RootGUID: TGUID absolute AdministratorGUID;      //alias of AdministratorGUID

7
投票

我尝试过这段代码:

  const
    CAnswer1 = 42;
    CAnswer2 : Integer = 42;

  var
    LAnswer : Integer;

  begin
    LAnswer := CAnswer1;
    LAnswer := CAnswer2;
  end;

这是生成的代码:

Project9.dpr.18: LAnswer := CAnswer1;
004101AC C7056C6E41002A00 mov [$00416e6c],$0000002a //<- assign a hard-coded "42" value
Project9.dpr.19: LAnswer := CAnswer2;
004101B6 A1701C4100       mov eax,[$00411c70] //<- fetch a variable's content
004101BB A36C6E4100       mov [$00416e6c],eax //<- assign this content 

你是对的:有些常数比其他常数更恒定。 第二个常量实际上被编译器视为变量。


5
投票
clHotlight: TColor = $00FF9933; 
          ^

通过

clHotlight
: 声明为“
变量
”(好吧,如果您在编译器选项中允许这样做,那么可以是“可分配常量”)。

正如您所发现的,声明:

clHotlight = TColor($00FF9933); 

在稍后指定之前不分配

clHotlight

这同样适用于您的 GUID。


4
投票

问题的出现是因为类型化常量并不是真正的常量,正如其他人以不同程度的清晰度和成功解释的那样。

尚未展示的是如何解决这个问题(在很多情况下),尽管有一对夫妇几乎要放弃这个秘密......:)

在您的具体情况下,您可以通过反转值的“别名”和类型化常量声明来解决问题,如下所示:

const
  clLink = $00FF9933;
  clHotlight: TColor = clLink;

clLink 现在提供您的真实常量,clHotlight 是与 clLink 具有相同值的类型化常量。

对于 GUID,可以使用相同的技术,但您必须记住用于初始化类型化 GUID 常量的普通常量表达式 - 它不使用记录,而是使用简单的文字字符串,因此:

const
  ID_CONSTANT = '{AA1C8AF2-C290-40AB-9CF5-2888A46E1660}';
  GUID_CONSTANT: TGUID = ID_CONSTANT;

注意: 这样的 GUID 常量在所有需要 TGUID 的地方都可以完美使用,例如IsEqualGUID( tguid, GUID_CONSTANT ) 等


3
投票

3
投票

常量声明的右侧必须是“常量表达式”,其定义为“常量表达式是编译器无需执行其所在程序即可计算的表达式”。您可以在语言指南中找到常量表达式的完整可接受语法。 请注意,语言指南明确指出“类型化常量不能出现在常量表达式中”。 - 这就是为什么你的声明失败,两个 clHotlight: TColor = $00FF9933;和管理员GUID:TGUID = ...;是类型常量。 此外,常量表达式不能包含除语言指南中列出的函数调用(即编译器能够在编译时计算的 Length()、SizeOf() 和其他一些函数调用)之外的函数调用。 这样重写:

const
  AdminGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
  AdministratorGUID: TGUID = AdminGUID;
  SuperuserGUID: TGUID = AdminGUID;

它会起作用的。


1
投票

欢迎来到德尔福进化。在delphi 1&2中,您不能将初始常量值分配给全局变量(例如:var xVar:Integer = 1)。您可以做到这一点的唯一方法是使用 const xVar: Integer = 1) 以及代码中的某些位置,然后您可以根据需要将其更改为其他内容。在他们摆脱这个古老的功能之前,您不能使用“const xVar:Integer”构造作为 const 值。

干杯 范

© www.soinside.com 2019 - 2024. All rights reserved.