【问题标题】:Why are global and static variables initialized to their default values?为什么将全局变量和静态变量初始化为其默认值?
【发布时间】:2011-01-06 16:24:13
【问题描述】:

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

为什么不留下垃圾值呢?有没有什么特别的 这是什么原因?

【问题讨论】:

    标签: c++ c static global-variables


    【解决方案1】:
    1. 安全性:不理会内存会泄露来自其他进程或内核的信息。

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

    3. 可重复性:不考虑这些值会使程序行为不可重复,从而很难找到错误。

    4. 优雅:如果程序可以从 0 开始,而无需使用默认初始化程序将代码弄乱,那就更简洁了。

    然后有人可能想知道为什么auto 存储类确实 以垃圾的形式开始。答案有两个:

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

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

    【讨论】:

    • 我猜提问者想知道为什么static int x; 总是让x 初始化为零,而int x;x 成为垃圾。
    • 其实真正的原因是最初的 C 标准是为了编纂现有的实践而不是引入新的东西。而 pre-ANSI/ISO C 这样做是为了提高效率。
    • DigitalRoss:“第一个堆栈帧”通常不是由您编写的代码使用,而是由标准库的程序序言和初始化例程使用。并不是每个操作系统都会在程序启动之前将堆栈(或堆!)内存归零 - 例如 MS-DOS 会(没有?)不会。
    • @DigitalRoss:即使您在为堆栈提供零填充页面的平台上(这很常见,但不一定普遍),这并不意味着第一次函数被调用,本地人将最终在零填充的内存中。例如,当调用main() 时,不知道在此之前运行时对堆栈做了什么。更不用说局部变量甚至可能不会出现在堆栈中(例如,它可能仅存在于寄存器中)。就 C/C++ 本地人而言,堆栈可能被零初始化是毫无意义的信息。
    • 不。对不起: 1.:错了。堆/堆栈未初始化,不会泄漏任何东西。 2.: 错误和错误:BSS 初始化需要时间并且 vals 不是没用的。 3.+4.:同意。第二个列表: 1.:错误。堆栈根本不保证从零开始。 2. 同意,但不回答问题。这正是在 C/C++ 中初始化内存的原因:运行时开销的优先级高于 C/C++ 中的安全/安全/优雅。对于全局变量,这种运行时开销可以忽略不计。 是对这个问题的回答:它的成本很低,但收益却很大,因此以这种方式指定。
    【解决方案2】:

    因为在 OS 的适当配合下,0 初始化静态和全局可以在没有运行时开销的情况下实现。

    【讨论】:

    • 在我们的代码开始执行之前初始化静态和全局变量,因此 mainCRTStartup() 或多或少有责任初始化它..
    • 存在运行时开销(操作系统必须用零填充页面),但无论如何出于安全原因需要它。
    • 这是错误的。请解释如何在没有运行时开销的情况下进行零初始化。你认为启动不是运行时间吗?
    【解决方案3】:

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

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

    ——如果是指针类型,则初始化为空指针;

    ——如果是算术类型,则初始化为(正或无符号)零;

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

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

    【讨论】:

    • 不回答 OP 的问题。这一切他都知道。他问为什么。 -1
    • 是的,如果问题中的“C/C++”表示 C/C++ 标准,我的回答是无关紧要的。否则,它是相关的。
    【解决方案4】:

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

    如果您没有对静态进行归零,那么您将在此阶段完全无法确定是否有任何东西被初始化,简而言之,C++ 世界将四分五裂,基本的东西,如单例(或任何类型)动态静态初始化)将简单地停止工作。

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

    【讨论】:

    • 关于单例的观点起初听起来很有说服力,但我不确定它是否真的有任何相关性:编译器如何存储他们的“已经创建的 y/n”标志是一个实现细节,他们会在启动之前肯定只能将 那些 归零。其余的过于轻率,没有真正解释自己。另外:the static one first right after the dynamic one 嗯?是静态的first?还是right after the dynamic one?有什么区别?此外,在对象相互依赖的所有情况下,无论存储时间长短,声明顺序都很重要,不是吗?
    【解决方案5】:

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

    来源:Wikipedia

    【讨论】:

    • 问题是为什么会发生这种情况。只是粘贴引用重复发生的事情并不能解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多