在 C++
中,我知道 静态
和 全局
对象会在 main
函数之前构造。但是你知道,在 C
中,不存在这种 main
函数之前的 初始化过程
。
例如,在我的代码中:
int global_int1 = 5;
int global_int2;
static int static_int1 = 4;
static int static_int2;
- 这四个变量何时被初始化?
- 编译期间像
5
和4
这样的初始化数值存储在哪里?如何在初始化时管理它们?
在 C++
中,我知道 静态
和 全局
对象会在 main
函数之前构造。但是你知道,在 C
中,不存在这种 main
函数之前的 初始化过程
。
例如,在我的代码中:
int global_int1 = 5;
int global_int2;
static int static_int1 = 4;
static int static_int2;
5
和4
这样的初始化数值存储在哪里?如何在初始化时管理它们?我推测你所说的静态和全局对象是指在命名空间作用域下定义的具有静态生命周期的对象。当这些对象在局部作用域下定义时,规则略有不同。
C++正式地将这样的变量初始化分为三个阶段: 1. 零初始化 2. 静态初始化 3. 动态初始化 语言还区分需要动态初始化和需要静态初始化的变量:所有静态对象(具有静态生命周期的对象)首先进行零初始化,然后进行静态初始化,最后进行动态初始化。
简单来说,动态初始化意味着必须执行某些代码;通常情况下,静态初始化不需要执行代码。因此:
extern int f();
int g1 = 42; // static initialization
int g2 = f(); // dynamic initialization
另一个近似的方式是静态初始化是C支持的(对于具有静态生存期的变量),动态初始化则适用于其他一切。
编译器如何执行这个操作当然取决于初始化方式,在基于磁盘的系统中,可执行文件从磁盘加载到内存中时,静态初始化的值是磁盘镜像的一部分,并由系统直接从磁盘加载。在经典的Unix系统上,全局变量将分为三个“段”:
我怀疑许多现代系统仍然使用类似的方法。
编辑:
另外一点说明:以上内容是针对C++03的。对于现有程序,C++11可能不会改变任何东西,但它确实添加了constexpr(这意味着某些用户定义的函数仍然可以是静态初始化)和线程本地变量,这就开启了一整个新的问题。
int i = f();
的语句,则可能在某些静态对象的构造函数中将 i
视为 0
,而在其他情况下则视为 f()
的返回值。 - James Kanze前言:在C++中,“static”一词有许多不同的含义。不要混淆。
您的所有对象都具有静态存储期,因为它们既不是自动的也不是动态的。(虽然线程局部变量有点像static)
在C++中,静态对象的初始化分为两个阶段:静态初始化和动态初始化。
动态初始化需要实际执行代码,因此对于以构造函数调用开头的对象或其中初始化程序是仅能在运行时评估的表达式的对象会进行动态初始化。
静态初始化是指已知初始化程序且不需要运行构造函数的初始化。(静态初始化要么是零初始化,要么是常量初始化)这适用于带有常量初始化程序的int变量,并且保证这些变量确实在静态阶段进行初始化。
(动态初始化的静态存储变量也会在其他任何操作发生之前静态零初始化。)
关键点在于静态初始化阶段根本不会“运行”。数据从一开始就存在。这意味着静态初始化没有任何“排序”或任何其他此类动态属性。如果您愿意,初始值已硬编码到您的程序二进制文件中。
main
开始之前。C没有进一步指定;在C++中,这些发生在静态初始化阶段,在构造函数或初始化器更复杂的对象之前。main
之前生成初始化每个变量的代码)。从标准中改写:
所有没有动态存储期、没有线程本地存储期且不是局部变量的变量都具有静态存储期。换句话说,所有全局变量都具有静态存储期。
具有动态初始化的静态对象不一定在主函数的第一个语句之前创建。这是实现定义的,即这些对象是在 main 函数的第一个语句之前创建,还是在与要初始化的静态变量定义在同一翻译单元中的任何函数或变量的第一次使用之前创建。
因此,在您的代码中,global_int1 和 static_int1 由于被静态初始化,所以它们肯定会在 main 函数的第一个语句之前初始化。然而,global_int2 和 static_int2 是动态初始化的,因此它们的初始化根据我上面提到的规则是实现定义的。
至于您的第二点,我不确定我理解您的意思。能否请您澄清一下?
std::string s = "abc";
并稍后从不同的 TU(或同一个 TU)访问它总是安全的。保证在访问时对象已被初始化。正确吗? - Aviv Cohn
main
函数之前有一个初始化过程,因为C规范中有说明(详见C99 5.1.2/1)。 - Mike Seymourgcc C++
不同,它并没有真正定义一个名为_start
的函数。 - Zachary