什么时候函数级静态variables被分配/初始化?

我相当确信,在程序开始的时候,全局声明的variables会被分配(并在适用的时候被初始化)。

int globalgarbage; unsigned int anumber = 42; 

但是在函数中定义的静态函数呢?

 void doSomething() { static bool globalish = true; // ... } 

globalish分配的空间是什么时候? 我正在猜测节目什么时候开始。 但是它也被初始化了吗? 或者当doSomething()被第一次调用时它被初始化了吗?

我很好奇,所以我写了下面的testing程序,并用g ++版本4.1.2进行编译。

 include <iostream> #include <string> using namespace std; class test { public: test(const char *name) : _name(name) { cout << _name << " created" << endl; } ~test() { cout << _name << " destroyed" << endl; } string _name; }; test t("global variable"); void f() { static test t("static variable"); test t2("Local variable"); cout << "Function executed" << endl; } int main() { test t("local to main"); cout << "Program start" << endl; f(); cout << "Program end" << endl; return 0; } 

结果不是我所期望的。 直到第一次调用该函数时才调用静态对象的构造函数。 这是输出:

 global variable created local to main created Program start static variable created Local variable created Function executed Local variable destroyed Program end local to main destroyed static variable destroyed global variable destroyed 

来自C ++标准的一些相关的语言:

3.6.2初始化非本地对象[basic.start.init]

1

具有静态存储持续时间的对象( basic.stc.static )的存储在进行任何其他初始化之前应该被初始化( dcl.init )。 在任何dynamic初始化发生之前,初始化具有用常量expression式( expr.const )初始化的具有静态存储持续时间的PODtypes( basic.types )的对象。 具有在同一个翻译单元中定义并dynamic初始化的静态存储持续时间的命名空间范围的对象应按其定义出现在翻译单元中的顺序进行初始化。 [注: dcl.init.aggr描述聚合成员初始化的顺序。 本地静态对象的初始化在stmt.dcl中描述。 ]

[下面的文字给编译器编写者增加了更多的自由]

6.7声明声明[stmt.dcl]

4

所有具有静态存储持续时间的本地对象( basic.stc.static )的零初始化( dcl.init )在进行任何其他初始化之前执行。 初始化一个具有静态存储持续时间的,使用常量expression式初始化的PODtypes( basic.types )的本地对象,在它的块被首次input之前进行初始化。 允许实现在静态存储持续时间内执行其他本地对象的早期初始化,这些条件允许在静态存储持续时间在命名空间范围( basic.start.init )中静态初始化一个对象。 否则,这样的对象在第一次通过声明时被初始化; 这样的对象在其初始化完成时被认为是初始化的。 如果通过抛出exception退出初始化,则初始化不完整,因此下一次控制进入声明时将再次尝试初始化。 如果控件在初始化对象时重新进入声明(recursion),则行为是未定义的。 [ 例如:

  int foo(int i) { static int s = foo(2*i); // recursive call - undefined return i+1; } 

结束示例 ]

具有静态存储持续时间的局部对象的析构函数只有当variables被构造时才会被执行。 [注意: basic.start.term描述了具有静态存储持续时间的本地对象被破坏的顺序。 ]

所有静态variables的内存都是在程序加载时分配的。 但是本地静态variables是在第一次使用时创build和初始化的,而不是在程序启动时。 这里有一些很好的关于这方面的知识和一般的静力学。 一般来说,我认为其中的一些问题取决于实现,特别是如果你想知道这个东西将在什么位置。

编译器会在程序加载时分配一个函数foo中定义的静态variables,但是编译器也会为你的函数foo添加一些额外的指令(机器代码),这样在第一次被调用的时候,这个额外的代码将初始化静态variables(例如调用构造函数,如果适用的话)。

@Adam:这个由编译器在后台注入代码是你看到结果的原因。

静态variables是在代码段内分配的 – 它们是可执行映像的一部分,所以映射到已经初始化的。

函数范围内的静态variables是相同的,范围是纯粹的语言级别构造。

出于这个原因,我们保证一个静态variables将被初始化为0(除非你指定了其他的东西),而不是一个未定义的值。

还有一些其他方面可以利用初始化 – 例如共享段允许一次运行不同的可执行程序实例来访问相同的静态variables。

在C ++(全局作用域)中,静态对象的构造函数在C运行时库的控制下作为程序的一部分启动。 在Visual C ++中,至less对象初始化的顺序可以由init_seg编译指示来控制。

或者当doSomething()被第一次调用时它被初始化了吗?

是的。 除此之外,这可以让您在适当时初始化全局访问的数据结构,例如在try / catch块内部。 例如,而不是

 int foo = init(); // bad if init() throws something int main() { try { ... } catch(...){ ... } } 

你可以写

 int& foo() { static int myfoo = init(); return myfoo; } 

并在try / catch块中使用它。 在第一次调用时,variables将被初始化。 然后,在第一次和下一次调用时,它的值将被返回(通过引用)。

我尝试再次testingAdam Pierce的代码,并添加了两个例子:类中的静态variables和PODtypes。 我的编译器是g ++ 4.8.1,在Windows操作系统(MinGW-32)中。 结果是类中的静态variables与全局variables相同。 它的构造函数在进入main函数之前会被调用。

  • 结论(对于g ++,Windows环境):

    1. 在进入函数(1)之前调用 :构造函数中的全局variables静态成员
    2. 本地静态variables :构造函数只在执行到第一次声明时被调用。
    3. 如果Local staticvariables是PODtypes ,那么在进入函数(1)之前,它也被初始化。 PODtypes示例: static int number = 10;

(1) :正确的状态应该是: “在调用同一翻译单元的任何function之前”。 但是,为了简单起见,如下例所示,则是主要function。

包括<iostream>

 #include < string> using namespace std; class test { public: test(const char *name) : _name(name) { cout << _name << " created" << endl; } ~test() { cout << _name << " destroyed" << endl; } string _name; static test t; // static member }; test test::t("static in class"); test t("global variable"); void f() { static test t("static variable"); static int num = 10 ; // POD type, init before enter main function test t2("Local variable"); cout << "Function executed" << endl; } int main() { test t("local to main"); cout << "Program start" << endl; f(); cout << "Program end" << endl; return 0; } 

结果:

 static in class created global variable created local to main created Program start static variable created Local variable created Function executed Local variable destroyed Program end local to main destroyed static variable destroyed global variable destroyed static in class destroyed 

任何人在Linux环境下testing?