delphi变量是不是默认初始化为一个值?

Posted

技术标签:

【中文标题】delphi变量是不是默认初始化为一个值?【英文标题】:Are delphi variables initialized with a value by default?delphi变量是否默认初始化为一个值? 【发布时间】:2010-09-13 01:28:25 【问题描述】:

我是 Delphi 的新手,我一直在运行一些测试来查看默认情况下初始化的对象变量和堆栈变量:

TInstanceVariables = class
  fBoolean: boolean; // always starts off as false
  fInteger: integer; // always starts off as zero
  fObject: TObject; // always starts off as nil
end;

这是我习惯于其他语言的行为,但我想知道在 Delphi 中依赖它是否安全?例如,我想知道它是否可能取决于编译器设置,或者可能在不同的机器上以不同的方式工作。依赖对象的默认初始化值是正常的,还是在构造函数中显式设置所有实例变量?

对于堆栈(过程级)变量,我的测试表明未初始化的布尔值是真的,未初始化的整数是 2129993264,未初始化的对象只是无效的指针(即不是 nil)。我猜规范是在访问它们之前始终设置过程级变量?

【问题讨论】:

两个注意事项: 1. 记录未初始化。 2. 引用计数变量总是被初始化。 !但!在返回字符串的函数中,'Result' 没有像您期望的那样初始化为空字符串。这是因为“结果”不是本地变量。所以,总是这样做:Result:= ''; 另见:Which variables are initialized when in Delphi? 【参考方案1】:

是的,这是记录在案的行为:

对象字段始终初始化为 0、0.0、''、False、nil 或任何适用的值。

全局变量也总是初始化为 0 等;

Local reference-counted* 变量始终初始化为 nil 或 '';

本地非引用计数* 变量未初始化,因此您必须先分配一个值才能使用它们。

我记得Barry Kelly 在某处写了一个“引用计数”的定义,但现在找不到了,所以在此期间应该这样做:

reference-counted == 本身是引用计数的,或者 直接或间接包含字段(用于记录)或元素(用于 引用计数的数组),例如:string, variant, interface动态数组静态数组 包含这些类型。

注意事项:

record 本身不足以成为引用计数 我还没有用泛型尝试过这个

【讨论】:

正如 Giacomo 在下面的 cmets 中指出的那样,这一切都在位于 ms-help://borland.bds4/bds4ref/html/Variables.htm 的 Delphi 帮助文件中进行了解释。在 Delphi 2009 中,我通过搜索“变量”的帮助找到了相同的信息(有趣的是,我尝试了很多搜索,但我没想过要尝试那个)。 如果局部变量属于托管类型,如字符串、接口、动态数组或变体,则已初始化 ($0) 不过有一个例外!当您覆盖构造函数并且不调用继承的构造函数时,有可能某些字段最终未初始化! (尤其是较旧的 Delphi 版本。)由于 TObject.Create 负责将所有数据归零,因此不调用它会导致可能的未知数据。 @WimtenBrink 我认为你错了。初始化不在 TObject.Create 中完成,这是一个 void 方法,而是在 class function TObject.InitInstance(Instance: Pointer): TObject; 中完成,它总是在任何构造函数调用之前调用,即使对于旧的 Delphi 版本也是如此。恕我直言,您的评论是错误且令人困惑的。 不要忘记,在一个返回字符串的函数中,'Result' 并没有像你期望的那样初始化为空字符串。这是因为“结果”不是本地变量。【参考方案2】:

没有显式初始化程序的全局变量分配在可执行文件的 BSS 部分中。它们实际上并不占用 EXE 中的任何空间; BSS 部分是操作系统分配并清零的特殊部分。在其他操作系统上,也有类似的机制。

您可以依赖零初始化的全局变量。

【讨论】:

【参考方案3】:

类字段默认为零。这已记录在案,因此您可以依赖它。 本地堆栈变量是未定义的,除非字符串或接口,它们被设置为零。

【讨论】:

谢谢。 “零”让我有点困惑——这是否意味着字符串是 '',而接口是 nil? 是的,就是这样。 nil = 0(在汇编程序级别)和 '' = nil(Delphi 约定)。 “除非字符串或接口”不是对现实的完整描述。例如,动态数组也会被初始化。更一般地说,规则是初始化托管(引用计数)类型的变量,即使是本地变量。 ...不要将本地堆栈变量Result混淆,参见***.com/q/5336863/2932052【参考方案4】:

附带说明(因为您是 Delphi 新手):全局变量可以在声明时直接初始化:

var myGlobal:integer=99;

【讨论】:

自 10.3 起同样适用于局部变量 如果没有显式做,则初始化为0、0.0、False、nil、[]等 @EdijsKolesnikovičs:使用什么语法(初始化局部变量)? VAR X : INTEGER = 0; 不起作用...(“错误 E2195 无法初始化局部变量”)【参考方案5】:

这是 Ray Lischners Delphi 的一句话简介Chapter 2

"Delphi第一次创建对象时,所有的字段一开始都是空的,即指针初始化为nil,字符串和动态数组为空,数值为零,布尔字段为False,设置Variants为 Unassigned。(详见第 5 章的 NewInstance 和 InitInstance。)"

确实需要初始化范围内的局部变量...在提供参考之前,我会将上面关于“全局变量已初始化”的评论视为可疑 - 我不相信。

编辑... Barry Kelly 说您可以依赖它们进行零初始化,并且由于他在 Delphi 编译器团队中,我相信这是有道理的 :) 谢谢 Barry。

【讨论】:

在delphi 2006帮助中你可以在这里找到它:ms-help://borland.bds4/bds4ref/html/Variables.htm "如果你没有显式初始化一个全局变量,编译器会初始化它为 0。对象实例数据(字段)也被初始化为 0。" 因为“我不相信”而被否决。这是编程,而不是宗教。而贾科莫刚刚证明了真相。【参考方案6】:

全局变量和对象实例数据(字段)始终初始化为零。 Win32 Delphi中没有初始化过程和方法中的局部变量;它们的内容是未定义的,直到您在代码中为它们分配一个值。

【讨论】:

【参考方案7】:

即使一种语言确实提供了默认初始化,我认为您也不应该依赖它们。初始化为一个值可以让其他可能不了解该语言的默认初始化的开发人员更加清楚,并防止跨编译器出现问题。

【讨论】:

当然可以。你应该。在每个构造函数中将所有内容初始化为 0/''/false/nil 是不必要的。另一方面,初始化全局变量并不是那么愚蠢——我有一次永远不记得它们是否被初始化(因为我没有经常使用它们)。 如果 Delphi 允许您在声明变量的同时初始化变量(例如 var fObject: TObject = nil),我倾向于同意初始化为一个值可能是个好主意。但对我来说,在构造函数中为每个对象字段做这件事似乎有点多。【参考方案8】:

来自 Delphi 2007 帮助文件:

ms-help://borland.bds5/devcommon/variables_xml.html

“如果没有显式初始化全局变量,编译器会将其初始化为0。”

【讨论】:

【参考方案9】:

我对给出的答案有点不满。 Delphi 将全局变量和新创建对象的内存空间清零。虽然这 NORMALLY 意味着它们已被初始化,但在一种情况下它们没有被初始化:具有特定值的枚举类型。如果零不是合法值怎么办?

【讨论】:

零始终是合法值,它是枚举的第一个值。你可以用 ord(MyFirstEnumValue) 看到它。 它将返回枚举类型中的第一个值。 如果你明确地为枚举赋值,零并不总是一个合法的值。在这种情况下,它仍然被初始化为 0,并且你有一个非法值。但是枚举只是普通整数类型上的语法糖,所以这并没有真正破坏任何东西。确保您的代码可以处理它。 @François:如果您像这样定义枚举,则不会:TOneTwoThree = (One=1, Two=2, Three=3);【参考方案10】:

新引入的(自 Delphi 10.3 起)内联变量使初始值的控制更加容易。

procedure TestInlineVariable;
begin
  var index: Integer := 345;
  ShowMessage(index.ToString);
end;

【讨论】:

以上是关于delphi变量是不是默认初始化为一个值?的主要内容,如果未能解决你的问题,请参考以下文章

C++中,类内的成员变量自动初始化为零吗,而全局变量随意赋值

将字节数组初始化为某个值,而不是默认的null? [复制]

java中怎么给变量初始化?

将可空整数初始化为默认值的最佳实践?

Swift 中未初始化变量/对象的默认值

默认初始化值初始化