默认情况下,delphi变量是否使用值初始化?


103

我是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)。我猜测规范是总是在访问它们之前设置过程级变量?


3
有两个注意事项:1.记录未初始化。2.引用计数的变量始终被初始化。!但!在返回字符串的函数中,“结果”未如您期望的那样初始化为空字符串。这是因为“结果”不是本地变量。因此,请始终执行:结果:='';
InTheNameOfScience


这回答了你的问题了吗?在Delphi中初始化哪些变量?
InTheNameOfScience

Answers:


105

是的,这是记录的行为:

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

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

  • 局部引用计数*变量始终初始化为nil或'';

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

我记得Barry Kelly在某个地方写了一个“引用计数”的定义,但是再也找不到了,因此在此期间应该这样做:

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

笔记:

  • record 本身不足以成为参考计数
  • 我还没有尝试过使用泛型

2
正如Giacomo在下面的评论中指出的那样,所有这些都在ms-help://borland.bds4/bds4ref/html/Variables.htm的Delphi帮助文件中进行了说明。在Delphi 2009中,我通过搜索“变量”的帮助找到了相同的信息(很有趣的是,我尝试了很多搜索,但是我不打算尝试那种搜索)。
MB。

8
如果局部变量属于托管类型(如字符串,接口,动态数组或变量),则将初始化它们($ 0)
Francesca

5
不过有一个例外!当您重写构造函数,并且不调用继承的构造函数时,有可能某些字段最终未初始化!(尤其是在较早的Delphi版本中。)由于TObject.Create负责将所有数据清零,因此,不调用该函数可能会导致未知数据。
Wim 10 Brink

18
@WimtenBrink我认为你错了。不会在内完成初始化TObject.Create,这是一个空方法,但class function TObject.InitInstance(Instance: Pointer): TObject;始终在任何构造函数调用之前调用它,即使对于较旧的Delphi版本也是如此。您的评论是恕我直言的错误和令人困惑。
Arnaud Bouchez

7
不要忘记,在返回字符串的函数中,“结果”未如您期望的那样初始化为空字符串。这是因为“结果”不是本地变量。
InTheNameOfScience 2015年

27

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

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


21

类字段默认为零。有文档记录,因此您可以依靠它。除非字符串或接口将其设置为零,否则未定义本地堆栈变量。


谢谢。“零”让我有些困惑-这是否意味着字符串是“”,而接口是零?
MB。

4
是的,就是这样。nil = 0(在汇编程序级别),而''= nil(Delphi约定)。
gabr

1
“除非字符串或接口”不是对现实的完整描述。例如,动态数组也会被初始化。更普遍的规则是,托管(引用计数)类型的变量即使是本地也要初始化。
安德烈亚斯·雷布兰德


7

这是Ray Lischners Delphi在《果壳》第2章中的引用

“当Delphi第一次创建对象时,所有字段都开始为空,即,指针初始化为nil,字符串和动态数组为空,数字的值为零,布尔字段为False,变量设置为未分配。 (有关详细信息,请参阅第5章中的NewInstance和InitInstance。)

的确,需要初始化局部作用域变量……我将上面的评论“全局变量已初始化”视为可疑,直到提供参考为止-我不相信这一点。

编辑... Barry Kelly说,您可以依靠它们将其初始化为零,并且由于他在Delphi编译器团队中,所以我相信这是正确的:)谢谢Barry。


1
在delphi 2006帮助中,您可以在这里找到它:ms-help://borland.bds4/bds4ref/html/Variables.htm“如果未显式初始化全局变量,则编译器会将其初始化为0。对象实例数据(字段)也初始化为0。”
Giacomo Degli Esposti

由于“我不相信”而被否决。这是编程,而不是宗教。贾科莫只是证明了事实。
InTheNameOfScience

6

全局变量和对象实例数据(字段)始终初始化为零。在Win32 Delphi中,不会初始化过程和方法中的局部变量。在您为代码分配值之前,它们的内容是不确定的。


5

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


4
当然可以。那你应该 不需要在每个构造函数中将所有内容初始化为0 /''/ false / nil。另一方面,初始化全局变量并不那么愚蠢-我曾经一次不记得它们是否已初始化(因为我使用它们的次数不多)。
gabr

2
如果Delphi让您在声明变量的同一点初始化变量(例如var fObject:TObject = nil),我倾向于同意初始化为一个值可能是个好主意。但是对我来说,在构造函数中为每个对象字段执行此操作似乎有些困难。
MB。

4

从Delphi 2007帮助文件中:

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

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


3

我对给出的答案有些不满。Delphi将全局变量和新创建的对象的存储空间清零。尽管这通常意味着它们已被初始化,但在某些情况下它们不是:带有特定值的枚举类型。如果零不是合法值怎么办?


1
零始终是合法值,它是枚举的第一个值。您可以使用ord(MyFirstEnumValue)看到它。
弗朗西斯卡

它将返回枚举类型的第一个值。
skamradt's

6
如果将值显式分配给枚举,则零并不总是合法值。在那种情况下,它仍然被初始化为0,并且您有一个非法值。但是枚举只是在普通整数类型上绘制的语法糖,因此这实际上并没有破坏任何东西。确保您的代码可以处理它。
梅森惠勒

2
@François:如果您这样定义枚举,则不会:TOneTwoThree = (One=1, Two=2, Three=3);
fnkr

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.