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

 
  1.  
  2.  
  3. extern "C" {

  4.  
  5. void dll_func() {

  6. foo_class::_.m += 100;

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

  8. }

  9.  
  10. }

编译选项:

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动态加载,而是通过编译时链接进去的话,也是构造了两次。
这里就不再另外贴出输出结果了。

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

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值