记一次BUG调试——静态链接库中全局变量/静态变量被重复初始化

记一次BUG调试——静态链接库中全局变量/静态变量被重复初始化

1 年前 · 来自专栏 编程语言

前言

源码本身非常的复杂,不容易简化,因此本文用最简单的实例来重现自己遇到的BUG,并分析其原因。

如下图,假设我们程序C.exe,需要两个库,分别是静态库A,和动态链接库B,并且B需要链接A,同时A中包含有全局/静态变量。

那么,此时就会出现A中的静态变量被初始化两次的问题,代码可以参考附录。

分析

这是因为C中包含A,那么C在执行main函数之前就会初始化A的全局变量;

又因为B中也有A,而C又动态加载了B,因此会再一次初始化A的全局变量(同样在执行main函数之前);


如果都是AB都是静态库,或者都是动态库,或者A是动态库,B是静态库,那么仅仅会初始化一次,即正常运行。

如果AB都是静态库,那么在构建C时,会根据依赖关系仅仅加载一次A;

如果A动态库,也只会被加载一次;

具体的深层次的原理,我并不清楚,需要深入的了解C/CPP程序编译链接的过程才行!

附录:

cmake:

cmake_minimum_required(VERSION 3.21)
project(test)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall")
add_library(A STATIC A.cpp)
add_library(B SHARED B.cpp)
target_link_libraries(B PRIVATE A)
add_executable(C main.cpp)
target_link_libraries(C PRIVATE A B)

main.cpp:

#include <cstdio>
#include "TEST1.h"
#include "TEST2.h"
int main() {
    printf("main()\n");
    ClassA::test();    // 本行保证和A够成链接关系
    ClassB b;          // 本行保证和B构成链接关系
    printf("main: END\n");
    return 0;

A.h:

#ifndef CLASSA_HPP
#define CLASSA_HPP
class ClassA
public:
    ClassA();
    ~ClassA();
    static void test();
#endif // CLASSA_HPP

A.cpp

#include <cstdio>
#include "TEST1.h"
ClassA A1;    // 我们在这里,定义了全局变量
ClassA::ClassA() {
    printf("ClassA\n");
ClassA::~ClassA() {
    printf("~ClassA\n");
void ClassA::test() {}

B.h

#ifndef CLASSB_HPP
#define CLASSB_HPP
#include "TEST1.h"
class ClassB
public:
    ClassB();
    ~ClassB();
    static void test();
#endif // CLASSB_HPP

B.cpp

#include <cstdio>
#include "TEST2.h"
ClassB::ClassB() {
    printf("ClassB\n");
ClassB::~ClassB() {
    printf("~ClassB\n");
void ClassB::test() {
    ClassA::test();      // 本行保证和A构成链接关系