静态变量初始化两次 [英] Static variable is initialized twice
问题描述
考虑一下,我在编译单元中有一个静态变量,该变量最终在 static 库libA中.然后,我有另一个编译单元访问此变量,该编译单元最终在 shared 库libB.so中(因此libA必须链接到libB中).最后,我有一个主要功能,也可以直接从A中访问与libB有依赖关系的静态变量和(因此,我链接到libA 和 libB).
Consider I have a static variable in a compilation unit which ends up in a static library libA. I then have another compilation unit accessing this variable which ends up in a shared library libB.so (so libA must be linked into libB). Finally I have a main function also accessing the static variable from A directly and having a dependency to libB (so I link against libA and libB).
然后我观察到,静态变量被初始化了两次,即其构造函数被运行了两次!这似乎是不对的.链接器不应该将两个变量都识别为相同的变量并将它们优化为一个变量吗?
I then observe, that the static variable is initialized twice, i.e. its constructor is run twice! This doesn't seem to be right. Shouldn't the linker recognize both variables to be the same and optimize them as one?
为了使我的困惑更加完美,我看到它用相同的地址运行了两次!那么也许链接器 did 可以识别它,但是没有删除static_initialization_and_destruction代码中的第二个调用吗?
To make my confusion perfect, I see it is run twice with the same address! So maybe the linker did recognize it, but did not remove the second call in the static_initialization_and_destruction code?
这是一个展示柜:
ClassA.hpp:
ClassA.hpp:
#ifndef CLASSA_HPP
#define CLASSA_HPP
class ClassA
{
public:
ClassA();
~ClassA();
static ClassA staticA;
void test();
};
#endif // CLASSA_HPP
ClassA.cpp:
ClassA.cpp:
#include <cstdio>
#include "ClassA.hpp"
ClassA ClassA::staticA;
ClassA::ClassA()
{
printf("ClassA::ClassA() this=%p\n", this);
}
ClassA::~ClassA()
{
printf("ClassA::~ClassA() this=%p\n", this);
}
void ClassA::test()
{
printf("ClassA::test() this=%p\n", this);
}
ClassB.hpp:
ClassB.hpp:
#ifndef CLASSB_HPP
#define CLASSB_HPP
class ClassB
{
public:
ClassB();
~ClassB();
void test();
};
#endif // CLASSB_HPP
ClassB.cpp:
ClassB.cpp:
#include <cstdio>
#include "ClassA.hpp"
#include "ClassB.hpp"
ClassB::ClassB()
{
printf("ClassB::ClassB() this=%p\n", this);
}
ClassB::~ClassB()
{
printf("ClassB::~ClassB() this=%p\n", this);
}
void ClassB::test()
{
printf("ClassB::test() this=%p\n", this);
printf("ClassB::test: call staticA.test()\n");
ClassA::staticA.test();
}
Test.cpp:
#include <cstdio>
#include "ClassA.hpp"
#include "ClassB.hpp"
int main(int argc, char * argv[])
{
printf("main()\n");
ClassA::staticA.test();
ClassB b;
b.test();
printf("main: END\n");
return 0;
}
然后我按如下所示进行编译和链接:
I then compile and link as follows:
g++ -c ClassA.cpp
ar rvs libA.a ClassA.o
g++ -c ClassB.cpp
g++ -shared -o libB.so ClassB.o libA.a
g++ -c Test.cpp
g++ -o test Test.cpp libA.a libB.so
输出为:
ClassA::ClassA() this=0x804a040
ClassA::ClassA() this=0x804a040
main()
ClassA::test() this=0x804a040
ClassB::ClassB() this=0xbfcb064f
ClassB::test() this=0xbfcb064f
ClassB::test: call staticA.test()
ClassA::test() this=0x804a040
main: END
ClassB::~ClassB() this=0xbfcb064f
ClassA::~ClassA() this=0x804a040
ClassA::~ClassA() this=0x804a040
有人可以解释一下这是怎么回事吗?链接器在做什么?相同变量如何初始化两次?
Can somebody please explain what is going on here? What is the linker doing? How can the same variable be initialized twice?
推荐答案
您正在将 libA.a
包含在 libB.so
中.这样, libB.so
和 libA.a
都包含定义静态成员的 ClassA.o
.
You are including libA.a
into libB.so
. By doing this, both libB.so
and libA.a
contain ClassA.o
, which defines the static member.
按照您指定的链接顺序,链接器从静态库 libA.a
中提取 ClassA.o
,因此, ClassA.o
初始化代码在 main()
之前运行.当访问动态 libB.so
中的第一个函数时,将运行 libB.so
的所有初始化程序.由于 libB.so
包括 ClassA.o
,因此必须再次运行 ClassA.o
的静态初始化程序.
In the link order you specified, the linker pulls in ClassA.o
from the static library libA.a
, so ClassA.o
initialization code is run before main()
. When the first function in the dynamic libB.so
is accessed, all initializers for libB.so
are run. Since libB.so
includes ClassA.o
, ClassA.o
's static initializer must be run (again).
可能的解决方法:
-
不要将ClassA.o放到libA.a和libB.so中.
Don't put ClassA.o into both libA.a and libB.so.
g++ -shared -o libB.so ClassB.o
不要同时使用这两个库;不需要libA.a.
Don't use both libraries; libA.a is not needed.
g++ -o test Test.cpp libB.so
应用以上任一方法均可解决问题:
Applying either of the above fixes the problem:
ClassA::ClassA() this=0x600e58
main()
ClassA::test() this=0x600e58
ClassB::ClassB() this=0x7fff1a69f0cf
ClassB::test() this=0x7fff1a69f0cf
ClassB::test: call staticA.test()
ClassA::test() this=0x600e58
main: END
ClassB::~ClassB() this=0x7fff1a69f0cf
ClassA::~ClassA() this=0x600e58
这篇关于静态变量初始化两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!