43

C++我所知staticglobal对象是在main函数之前构造的。但如您所知,在,以前C没有这种类型。initialization proceduremain

例如,在我的代码中:

int global_int1 = 5;
int global_int2;
static int static_int1 = 4;
static int static_int2;
  • 这四个变量什么时候初始化
  • 初始化的值54在编译期间存储在哪里?初始化时如何管理它们?

编辑:
澄清第二个问题。

  • 在我的代码中我5用来初始化 global_int1,那么编译器如何分配 5global_int?例如,也许编译器首先将5值存储在某个地方(即表),并在初始化开始时获取该值。
  • 至于“初始化时如何管理它们?”,它真的很模糊,我自己还没有如何解释。有时,解释一个问题并不容易。忽略它,因为我还没有完全掌握这个问题。
4

4 回答 4

27

我认为静态和全局对象是指在命名空间范围内定义的具有静态生命周期的对象。当使用本地范围定义此类对象时,规则略有不同。

形式上,C++ 分三个阶段初始化这些变量: 1. 零初始化 2. 静态初始化 3. 动态初始化 该语言还区分需要动态初始化的变量和需要静态初始化的变量:所有静态对象(具有静态生命周期的对象)都是首先初始化零,然后初始化静态初始化的对象,然后进行动态初始化。

作为一个简单的初步近似,动态初始化意味着必须执行一些代码;通常,静态初始化不会。因此:

extern int f();

int g1 = 42;    //  static initialization
int g2 = f();   //  dynamic initialization

另一个近似值是静态初始化是 C 支持的(对于具有静态生命周期的变量),其他一切都是动态的。

当然,编译器如何做到这一点取决于初始化,但在基于磁盘的系统上,可执行文件从磁盘加载到内存中,静态初始化的值是磁盘上图像的一部分,并由系统直接从磁盘。在经典的 Unix 系统上,全局变量将分为三个“段”:

文本:
代码,加载到写保护区。`const` 类型的静态变量也将被放置在这里。
数据:
带有静态初始化器的静态变量。
bss:
无初始化器(C 和 C++)或动态初始化(C++)的静态变量。可执行文件不包含此段的图像,系统在启动代码之前将其全部设置为“0”。

我怀疑许多现代系统仍然使用类似的东西。

编辑:

补充一点:以上是指 C++03。对于现有的程序,C++11 可能不会改变任何东西,但它确实添加了constexpr(这意味着一些用户定义的函数仍然可以是静态初始化)和线程局部变量,这开辟了一个全新的蠕虫罐。

于 2013-07-22T10:17:02.707 回答
19

前言:“静态”这个词在 C++ 中有大量不同的含义。不要混淆。

您所有的对象都有静态存储持续时间。那是因为它们既不是自动的也不是动态的。(也不是线程局部的,虽然线程局部有点像静态的。)

在 C++ 中,静态对象的初始化分为两个阶段:静态初始化和动态初始化。

  • 动态初始化需要执行实际代码,因此这发生在以构造函数调用开头的对象,或者初始化程序是只能在运行时计算的表达式的情况下。

  • 静态初始化是指静态已知初始化程序并且不需要运行构造函数。(静态初始化是零初始化常量初始化。)对于具有常量初始化器的变量就是这种情况int,并且您可以保证这些变量确实在静态阶段被初始化。

  • (具有动态初始化的静态存储变量也在其他任何事情发生之前静态初始化为零。)

关键点是静态初始化阶段根本没有“运行”。数据从一开始就在那里。这意味着没有“排序”或任何其他涉及静态初始化的动态属性。如果您愿意,初始值会被硬编码到您的程序二进制文件中。

于 2013-07-22T10:19:28.413 回答
5

这四个变量是什么时候初始化的?

正如你所说,这发生在程序启动之前,即main开始之前。C 没有进一步说明;在 C++ 中,这些发生在具有更复杂的构造函数或初始化程序的对象之前的静态初始化阶段。

在编译期间将初始化值(如 5 和 4)存储在哪里?

通常,非零值存储在程序文件的数据段中,而零值存储在bss段中,它为变量保留足够的内存。当程序启动时,数据段被加载到内存中,bss段被设置为零。(当然,语言标准没有指定这一点,所以编译器可以做其他事情,比如在运行之前生成代码来初始化每个变量main)。

于 2013-07-22T09:18:04.523 回答
3

引用标准:

所有没有动态存储持续时间、没有线程本地存储持续时间和不是本地的变量都具有静态存储持续时间。换句话说,所有全局变量都有静态存储持续时间。

动态初始化的静态对象不一定要在主函数的第一条语句之前创建。这些对象是在 main 中的第一条语句之前创建的,还是在第一次使用与要初始化的静态变量在同一翻译单元中定义的任何函数或变量之前创建的,由实现定义。

因此,在您的代码中, global_int1 和 static_int1 肯定在 main 中的第一条语句之前初始化,因为它们是静态初始化的。但是 global_int2 和 static_int2 是动态初始化的,所以它们的初始化是根据我上面提到的规则定义的实现。

至于你的第二点,我不确定我明白你的意思。你能澄清一下吗?

于 2013-07-22T09:13:00.220 回答