视觉C++:在 DLL 加载期间,全局变量初始化顺序是否具有确定性?

Visual C++: Is global variables initialization order deterministic during DLL loading?

本文关键字:是否 顺序 初始化 确定性 全局变量 C++ DLL 加载 视觉      更新时间:2023-10-16

>假设我构建了一个简单的DLL,由两个翻译单元组成:

第一

// foo.cpp
struct Foo
{
//...
} g_foo;
// ... other stuff

第二个

// bar.cpp
struct Bar
{
//...
} g_bar;
// ... other stuff

我知道C++标准没有指定全局变量初始化的顺序。问题是:一旦我有了构建的 Windows DLL,在调用期间执行的全局变量初始化顺序是确定性的LoadLibrary(每个LoadLibrary调用都会以相同的顺序启动变量g_foog_bar的初始化(还是可能取决于某些加载器/系统设置?

我知道

C++标准没有指定顺序 全局变量初始化。 准确地说,当全局变量位于单个翻译单元中时,它会这样做:

有序动态初始化,适用于所有其他非本地 变量:在单个翻译单元中,初始化这些变量 变量总是按照其定义的精确顺序排序 出现在源代码中。

上面的 DLL 代码,在两个不同的翻译单元中有两个不同的全局变量,将导致两个不同的 .链接前的 OBJ 文件。然后,当 .OBJ 文件链接在一起形成一个.DLL,C++"pre-main"运行时代码将附加到.DLL。当.DLL通过进程启动或LoadLibrary绑定到进程的地址空间时,此存根代码将有权访问 DLL 中的一个表,在调用 DllMain 之前,它将遍历、调用表中链接时间合成的静态非成员函数,每个非成员函数的任务是在表中为相应的全局对象运行类成员构造函数。当然,在从进程地址空间中删除 DLL 期间,无论是通过进程退出还是通过FreeLibrary,非成员函数都将以类似的方式调用,但顺序相反 (LIFO(。

鉴于此表由 LINK.EXE "烘焙"到.DLL中,DLL 中全局变量的构造顺序(无论它们来自同一转换单元还是不同(都将预先确定。正如您所指出的,它在链接时间之前是不可预测的,但是无论它在链接时间之后变成什么,它都会在.DLL的生命周期中保留下来,因为只有 LINK.EXE 有能力构造该全局变量构造函数表,一旦构造它,它就会被构造。

如果有人想知道哪个先来:全局变量的构造,还是程序员提供的DllMain,那就是前者。C++运行时代码调用程序员提供的 DllMain,如 @Algirdas Preidžius 提供的链接所示。

相关文章: