2015-11-10 104 views
1

我在CentOS 6.5上遇到过。正如我在网上搜索的那样,当使用动态库时,静态变量在Windows和Linux上的行为不同。也就是说,Windows会导致变量的重复,Linux不会像这样:但是,当我编写一个小程序来验证这一点时,我发现Linux也会导致重复。这是我的小程序,包括四个文件:静态变量和全局变量在Linux上的动态库和静态库中显示不同的地址?

(1)阿

#ifndef A_H 
#define A_H 
#include <cstdio> 
static int b; 
extern "C" class A { 
    public: 
    int mem; 
    A() { 
     printf("A's address: %p\n", this); 
     printf("B's address: %p\n", &b); 
    } 
    void print() { 
     printf("%p: %d\n", this, mem); 
    } 
    ~A() { 
     printf("DELETE A!!!!! %p\n", this); 
    } 
}; 
extern A a; 
#endif 

(2)A.cpp

#include "A.h" 
A a; 

(3)d .cpp

#include "A.h" 
extern "C" void exec() { 
    a.print(); 
} 

(4)的main.cpp

#include "A.h" 
#include <dlfcn.h> 
typedef void (*fptr)(); 
int main() { 
    a.mem = 22; 
    a.print(); 
    void *handle; 
    handle = dlopen("d.so", RTLD_LAZY); 
    fptr exec = reinterpret_cast<fptr>(dlsym(handle, "exec")); 
    (*exec)(); 
    dlclose(handle); 
    return 0; 
} 

这是我如何编译和运行我的程序:

g++ d.cpp A.cpp -shared -rdynamic -o d.so -ldl -I. -fPIC -g -std=c++1y 
g++ main.cpp A.cpp -ldl -I. -g -std=c++1y 
./a.out 

两个动态部分d.cpp和静态部分main.cpp使用A.cppA.h中声明的变量ab。这里是我的机器上的程序的结果是:

A's address: 0x600f8c 
B's address: 0x600f90 
0x600f8c: 22 
A's address: 0x7fb8fe859e4c 
B's address: 0x7fb8fe859e50 
0x7fb8fe859e4c: 0 
DELETE A!!!!! 0x7fb8fe859e4c 
DELETE A!!!!! 0x600f8c 

这让我吃惊了很多,因为全局变量a和静态变量b的地址应该是在动力部分和相同静态部分。而且在静态部分a上的修改似乎不影响动态部分中的a。任何人都请回答我的问题,或帮助找出程序中的一些错误(如果有的话)?顺便说一下,说实话,在我正在开发的另一个项目中,我发现全局变量的地址在动态库和静态库中是相同的。但是这个项目太大了,我无法提供一个小程序来重现这种行为。

非常感谢!

回答

0

您显示的第一条命令会生成一个共享对象d.so。根据你的问题的背景,我推测你也打算链接d.so,但你的第二个命令似乎缺少那部分。我假设它是一个错字,因为这是您显示的程序输出的唯一解释 - A.cpp既直接链接,也内置于您的d.so库中。

鉴于这种情况,从你链接的文章引用:

双方使用的对象代码例程不应该在每次重复。 对于使用静态变量(如 单例类)的代码尤其如此。一个静态变量是全局的,因此只能代表一次 。包括它两次将提供意想不到的结果。

但是,这正是你似乎被打破,你代表的A类的静态范围的情况下的两倍,在你d.so,并在主应用程序的可执行规则。

所以,这似乎是显示的结果:“意想不到的结果”。

+0

感谢您的回答!你是对的。第一个cmd行生成一个'd.so',但我认为我没有把它链接到一个错误的方式。有两种方法可以链接一个动态库。一种是在编译程序时连接,另一种是使用'dlopen','dlsym'和'dlclose'。 (http://linux.die.net/man/3/dlopen)我使用后者,如'main.cpp'所示。 (我的意思是这不是一个错字,cmd行可以在我的机器上执行^ _ ^)。但是......你确实让我想到'dlopen'是否会导致目标代码例程的重复。 –

+0

dlopen - 绝对。 dlopen打开指定的共享库并将其映射到可执行文件的地址空间中。 dlopen绝对没有任何逻辑来确定可执行文件是否定义了与共享库相同的符号,并且不知何故不会从共享库中加载它们。整个库都被加载,或者不是。 –

+0

'dlopen'确实在动态部分创建了全局变量的新副本,这与静态部分不同。 –