考虑我在编译单元中有一个静态变量,最终会被打包成静态库libA。然后,我有另一个编译单元访问此变量,最终会被打包成共享库libB.so(所以必须将libA链接到libB中)。最后,我还有一个主函数直接从A访问静态变量,并且依赖于libB(因此我同时链接了libA和libB)。
然后我观察到,静态变量被初始化两次,也就是说它的构造函数运行了两次! 这似乎不对。难道链接器不能识别这两个变量为同一个并将它们优化为一个吗?
为了让我的困惑更加完美,我发现它使用相同的地址运行了两次!所以也许链接器确实识别了它,但没有在静态初始化和销毁代码中删除第二个调用?
以下是一个示例:
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:
#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:
#ifndef CLASSB_HPP
#define CLASSB_HPP
class ClassB
{
public:
ClassB();
~ClassB();
void test();
};
#endif // CLASSB_HPP
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;
}
我接下来按照以下步骤进行编译和链接:
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
可以有人解释一下这里正在发生什么吗?链接器在做什么?同一个变量怎么可能被初始化两次?
A
和B
都设置为静态库或共享库,则不会出现此问题(A
的构造函数仅运行一次)。但是,我希望链接器能够识别和消除重复的符号和初始化调用。我的假设是错误的还是链接器有问题? - bselu