gpt4 book ai didi

c++ - 与静态库链接与在 C++ 中使用对象文件时的不同行为

转载 作者:搜寻专家 更新时间:2023-10-31 00:56:54 24 4
gpt4 key购买 nike

我正在处理一些以我不理解的方式运行的遗留 C++ 代码。我使用的是 Microsoft 编译器,但我也尝试过使用 g++(在 Linux 上)——同样的行为。

下面列出了 4 个文件。本质上,它是一个跟踪成员列表的注册表。如果我编译所有文件并将目标文件链接到一个程序中,它会显示正确的行为:registry.memberRegistered 为真:

>cl shell.cpp registry.cpp member.cpp
>shell.exe
1

所以 member.cpp 中的代码以某种方式被执行(我不是很理解,但是没关系)。

但是,我想要的是从 registry.cpp 和 member.cpp 构建一个静态库,并将其链接到从 shell.cpp 构建的可执行文件。但是当我这样做时,member.cpp 中的代码不会被执行并且 registry.memberRegistered 为 false:

>cl registry.cpp member.cpp  /c
>lib registry.obj member.obj -OUT:registry.lib
>cl shell.cpp registry.lib
>shell.exe
0

我的问题:为什么它以第一种方式而不是第二种方式工作,是否有办法(例如编译器/链接器选项)使其以第二种方式工作?


注册表.h:

class Registry {
public:

static Registry& get_registry();
bool memberRegistered;

private:
Registry() {
memberRegistered = false;
}
};

注册表.cpp:

#include "registry.h"
Registry& Registry::get_registry() {
static Registry registry;
return registry;
}

成员.cpp:

#include "registry.h"

int dummy() {
Registry::get_registry().memberRegistered = true;
return 0;
}
int x = dummy();

shell.cpp:

#include <iostream>
#include "registry.h"

class shell {
public:
shell() {};
void init() {
std::cout << Registry::get_registry().memberRegistered;
};
};
void main() {
shell *cf = new shell;
cf->init();
}

最佳答案

您被众所周知的 static initialization order fiasco击中了。 .基本原理是跨翻译单元的静态对象的初始化顺序是未指定的。参见 this

<罢工>

这里调用 Registry::get_registry().memberRegistered;"shell.cpp" 中可能发生在调用此处 int x = dummy(); 之前在 “member.cpp”

编辑:

嗯,x不是 ODR-used .因此,允许编译器不评估 int x = dummy();在输入 main() 之前或之后,甚至根本没有。

只是来自 CppReference 的引述(强调我的)

It is implementation-defined whether dynamic initialization happens-before the first statement of the main function (for statics) or the initial function of the thread (for thread-locals), or deferred to happen after.

If the initialization is deferred to happen after the first statement of main/thread function, it happens before the first odr-use of any variable with static/thread storage duration defined in the same translation unit as the variable to be initialized. If no variable or function is odr-used from a given translation unit, the non-local variables defined in that translation unit may never be initialized (this models the behavior of an on-demand dynamic library)...


让你的程序按你想要的方式工作的唯一方法是确保 x是否使用 ODR

shell.cpp

#include <iostream>
#include "registry.h"

class shell {
public:
shell() {};
void init() {
std::cout << Registry::get_registry().memberRegistered;
};
};

extern int x; //or extern int dummy();

int main() {
shell *cf = new shell;
cf->init();
int k = x; //or dummy();
}

^ 现在,您的程序应该按预期运行。 :-)

关于c++ - 与静态库链接与在 C++ 中使用对象文件时的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38469951/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com