为什么将全局变量和静态变量初始化为其默认值?


69

在C / C ++中,为什么将全局变量和静态变量初始化为默认值?

为什么不只留下垃圾值呢?有什么特殊原因吗?

Answers:


76
  1. 安全性:单独保留内存会泄漏其他进程或内核的信息。

  2. 效率:在将值初始化为某种值之前,这些值是无用的,并且在具有展开循环的块中将它们归零会更有效。当系统空闲时,而不是在某些客户端或用户正在等待程序启动时,操作系统甚至可以将空闲列表页面清零。

  3. 可重现性:单独保留这些值将使程序行为不可重复,从而使错误很难发现。

  4. 优雅:如果程序可以从0开始,而不必使用默认的初始化程序使代码混乱,则更加简洁。

然后,您可能会想知道为什么auto存储类确实会作为垃圾启动。答案有两个:

  1. 某种意义上讲不是。每个级别的第一个堆栈帧页面(即,添加到堆栈中的每个新页面)的确接收零值。同一堆栈级别的后续函数实例看到的“垃圾”或“未初始化”值实际上是您自己的程序及其库的其他方法实例留下的先前值。

  2. 与初始化任何东西(函数局部变量)有关,可能会有二次(或其他)运行时性能损失auto。一个函数可能不使用任何大数组中的任何一个或全部,例如,在任何给定的调用中,它可能被调用数千或数百万次。静态和全局变量OTOH的初始化只需发生一次。


6
我猜问问问者想知道为什么static int x;总是在x将其设为垃圾的同时int x;x其初始化为零。
kennytm 2010年

3
实际上,真正的原因是原始的C标准是对现有实践进行整理而不是引入新的东西。ANSI / ISO C之前的版本是为了提高效率。
paxdiablo 2010年

3
DigitalRoss:您编写的代码通常不使用“第一个堆栈框架”,而是标准库的程序序言和初始化例程使用它。并非每个操作系统都在程序启动之前将堆栈(或堆!)内存清零-例如,MS-DOS不会(不是吗?)。
caf 2010年

3
@DigitalRoss:即使您使用的平台为堆栈提供零填充页面(这是很常见的,但不一定是通用的),这并不意味着第一次调用该函数将导致本地人结束在零填充的内存中。例如,在main()调用when时,没有告诉运行时在那之前对堆栈做了什么。更不用说局部变量甚至可能不会出现在堆栈中(例如,它可能仅存在于寄存器中)。就C / C ++本地而言,栈可能被零初始化是无意义的信息。
Michael Burr 2010年

2
不。抱歉:1 .:错误。堆/堆栈未初始化,不会泄漏任何东西。2 .:错误和错误:BSS初始化需要时间,并且val并非没有用。3. + 4:同意。第二个列表:1 .:错误。堆栈不保证从零开始。2.同意但不能回答问题。这正是使用C / C ++初始化内存的原因:运行时开销的优先级高于C / C ++中的安全性/安全性/优雅性。对于全局变量,此运行时开销可以忽略不计。就是问题的答案:它具有极低的成本和巨大的收益,因此它是用这种方式指定的。
约翰尼斯·奥弗曼

27

因为通过操作系统的适当配合,可以在没有运行时开销的情况下实现0初始化静态变量和全局变量。


而且静态和全局变量是我们的代码开始执行之前初始化,因此更或mainCRTStartup()的责任,少来初始化它..
布佩希裤

1
运行时开销很大(操作系统必须用零填充页面),但是出于安全考虑,还是需要它。
user253751 '20

错了 请说明如何在没有运行时开销的情况下完成零初始化。您是否认为启动不是运行时?
robsn

17

第6.7.8节C99标准(n1256)的初始化回答了这个问题:

如果具有自动存储期限的对象未明确初始化,则其值不确定。如果未明确初始化具有静态存储持续时间的对象,则:

—如果具有指针类型,则将其初始化为空指针;

—如果具有算术类型,则将其初始化为(正数或无符号)零;

—如果是集合,则根据这些规则(递归)初始化每个成员;

—如果是联合,则根据这些规则(递归)初始化第一个命名成员。


8
不回答OP的问题。他知道这一切。他问为什么。-1
user207421 2014年

3
是的,如果问题中的“ C / C ++”表示C / C ++标准,那么我的回答是无关紧要的。否则,它是相关的。
蒋经国姚明

7

想一想,在静态领域中,您无法始终确保某些内容确实已初始化,或者该main已经启动。还有一个静态init和一个动态init阶段,在动态重要的顺序之后,静态一个优先。

如果您没有对静态进行归零,那么您将无法在此阶段完全确定是否已对AT ALL进行了初始化,总之,C ++世界将飞散,而诸如单例(或任何类型的动态静态)之类的基本事物将飞散。 init)简单地停止工作。

要点的答案很热情,但有点愚蠢。这些都可能适用于非静态分配,但没有做到(很好,有时但不是通常)。


最初关于单例的观点听起来很引人注目,但我不确定它实际上是否有任何相关性:编译器如何存储其“已经创建的y / n”标志是实现细节,并且肯定可以将那些先前的零置为零。启动。其余的过于轻率,没有真正说明自己。还:the static one first right after the dynamic one哇?是静态的first吗?还是right after the dynamic one?有什么区别?而且,在对象相互依赖的所有情况下,不管存储时间长短,声明的顺序都很重要,不是吗?
underscore_d

3

在C中,没有显式初始化程序的静态分配对象被初始化为零(对于算术类型)或空指针(对于指针类型)。C的实现通常使用仅由零值位组成的位模式来表示零值和空指针值(尽管C标准不需要)。因此,bss部分通常包括在文件范围内声明的所有未初始化变量(即,在任何函数外部)以及使用static关键字声明的未初始化局部变量。

资料来源:维基百科


2
问题是为什么会这样。仅粘贴重复出现的情况的引用并不能解决问题。
underscore_d
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.