为什么静态变量自动初始化为零?

时间:2010-07-30 15:45:04

标签: c

  

可能重复:
  Why global and static variables are initialized to their default values?

出现这种情况的技术原因是什么?所有平台的标准都支持它吗?如果没有显式初始化静态变量,某些实现是否可能返回未定义的变量?

7 个答案:

答案 0 :(得分:35)

标准要求 (§6.7.8/ 10)。

没有任何技术原因会让 以这种方式出现,但是这种方式已经足够长,以至于标准委员会将其作为一项要求。

在许多(大多数?)情况下,放弃这个要求会使静态变量的处理变得更加困难。特别是,您经常要进行一次初始化,并且需要一个可靠的起始状态,以便您知道某个特定变量是否已初始化。例如:

int foo() { 
    static int *ptr;

    if (NULL == ptr)
       // initialize it
}

如果ptr在启动时可能包含任意值,则必须将其显式初始化为NULL,以便能够识别您是否已完成一次性初始化。

答案 1 :(得分:10)

是的,这是因为它符合标准;但实际上,这是因为它是免费的。静态变量看起来就像生成的对象代码的全局变量。它们在.bss中分配,并在加载时与所有常量和其他全局变量一起初始化。由于它们所在的内存部分只是直接从您的可执行文件中复制而来,因此它们在编译时被初始化为免费已知的值。选择的值为0.

答案 2 :(得分:1)

当然,没有人认为它符合C标准。因此,期望兼容的编译器以这种方式运行。

完成原因的技术原因可能根植于C启动代码的工作原理。链接器通常有几个内存段将编译器输出放入其中,包括代码(文本)段,块存储段和初始化变量段。

非静态函数变量在运行时创建函数范围之前没有物理存储,因此链接器不会对它们执行任何操作。

程序代码当然是代码(或文本)段,但用于初始化全局变量和静态变量的也是如此。初始化变量本身(即它们的地址)进入初始化的存储器段。未初始化的全局变量和静态变量进入块存储(bss)段。

在执行时加载程序时,一小段代码会创建C运行时环境。在基于ROM的系统中,它将初始化变量的从代码(文本)段复制到RAM中各自的实际地址中。基于RAM(即磁盘)的系统可以将初始值直接加载到最终的RAM地址。

CRT(C运行时)也将包含所有没有初始值设定项的全局变量和静态变量的bss清零。这可能是作为预防未初始化数据的预防措施。这是一个相对简单的块填充操作,因为所有的全局变量和静态变量都被塞在一个地址段中。

当然浮点数和双精度可能需要特殊处理,因为如果浮动格式不是IEEE 754,它们的0.0值可能不是全零位。

请注意,由于自动变量在程序加载时不存在,因此运行时启动代码无法初始化

答案 3 :(得分:0)

主要是因为链接器将静态变量组合在一个块中,因此在启动时将整个块memset()简化为0非常容易。我不相信C或C ++标准要求。

答案 4 :(得分:0)

有关于此here的讨论:

  

首先,在ISO C(ANSI C)中,必须在程序启动之前初始化所有静态和全局变量。如果程序员没有明确地这样做,那么编译器必须将它们设置为零。如果编译器没有这样做,它就不会遵循ISO C.但是,标准没有指定变量初始化的确切方式。

答案 5 :(得分:0)

看看:here 6.2.4(3)和6.7.8(10)

答案 6 :(得分:0)

假设您正在编写C编译器。您希望某些静态变量具有初始值,因此这些值必须出现在编译器要创建的可执行文件中的某个位置。现在,当运行输出程序时,整个可执行文件将加载到内存中。程序初始化的一部分是创建静态变量,因此必须将所有这些初始值复制到其最终的静态变量目标。

或者他们呢?程序启动后,不再需要变量的初始值。变量本身不能位于可执行代码本身内吗?然后,无需复制值。静态变量可以存在于原始可执行文件中的块中,并且根本不需要对它们进行初始化。

如果是这种情况,那么为什么要为未初始化的静态变量创建一个特例?为什么不在可执行文件中放入一堆零来表示未初始化的静态变量?这会在一段时间内交换一些空间,而且复杂性会降低很多。

我不知道任何C编译器是否真的以这种方式运行,但我怀疑以这种方式做事的选择可能会推动语言的设计。