欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > c/c++ >内容正文

c/c++

C++又一坑:动态链接库中的全局变量

发布时间:2025/3/21 c/c++ 45 豆豆
生活随笔 收集整理的这篇文章主要介绍了 C++又一坑:动态链接库中的全局变量 小编觉得挺不错的,现在分享给大家,帮大家做个参考.
  •  
  •  
  • extern "C" {

  •  
  • void dll_func() {

  • foo_class::_.m += 100;

  • printf("&foo_class::_ = 0x%llx, foo_class::_.m = %d\n", &foo_class::_, foo_class::_.m);

  • }

  •  
  • }

  • 编译选项:

    gcc -O0 -g -ggdb c.cpp -o libtest_c.so -shared -fPIC -L$PWD -ltest_a -lstdc++

    这是三个模块的代码和编译选项。我分别至于Linux和Windows内的GCC编译测试。
    Linux中的GCC 4.4.6 运行结果如下:

    foo_class::foo_class(), this-> 0x600f98
    &foo_class::_ = 0x600f98, foo_class::_.m = 1010
    foo_class::foo_class(), this-> 0x600f98
    &foo_class::_ = 0x600f98, foo_class::_.m = 110
    foo_class::~foo_class(), this-> 0x600f98
    foo_class::~foo_class(), this-> 0x600f98

    从结果中可以看出来,在Linux中多个动态链接库和主程序引用的同一个全局变量(地址相同),但是每一个二进制实例都会完成一次构造。这就造成了同一个实例多次构造,导致我们最初碰到的结果。

    Windows中Cygwin的GCC 4.8.2 中运行结果如下:

    foo_class::foo_class(), this-> 0x100406010
    &foo_class::_ = 0x100406010, foo_class::_.m = 1010
    foo_class::foo_class(), this-> 0x5aa426010
    &foo_class::_ = 0x5aa426010, foo_class::_.m = 110
    foo_class::~foo_class(), this-> 0x5aa426010
    foo_class::~foo_class(), this-> 0x100406010

    但是在Windows中,虽然每个动态链接库和主程序引用的同一个全局变量也各自都执行了一次构造。但是,每一个二进制内的全局变量,实际上并不是同一个。他们并不冲突,但是他们也不在一个内存区域内,所以即便是纯C下和Linux内的行为也不一样。

    这也就意味着,在Linux中,载入的动态链接库实际上可以直接使用外部框架或者其他模块的全局数据,但是在Windows下确是隔离的,不能直接访问到。
    另外, 我从另一篇文章上看到,这个行为与dlopen时flag是RTLD_GLOBAL还是RTLD_LOCAL有关。但是我这里实测没有任何变化。但是结果和编译选项-fPIC有关(原因去看gcc文档吧,我就不复述啦)。
    PS: 如果不是直接使用的全局变量,而是直接使用函数接口,并且返回一个static的局部变量这种方式,测试结果也是一样的;
    而且如果不是通过dlopen动态加载,而是通过编译时链接进去的话,也是构造了两次。
    这里就不再另外贴出输出结果了。

    其实,根本问题是多个动态链接库里共享的内存对象的构造问题。在不同环境下有不同的行为,也许会藏地比较隐晦。着实是个坑呐。

    总结

    以上是生活随笔为你收集整理的C++又一坑:动态链接库中的全局变量的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。