2

我在 CentOS 6.5 上遇到过。正如我在网上搜索的那样,静态变量在使用动态库时在 Windows 和 Linux 上的行为不同。也就是说,Windows 会导致变量重复,而 Linux 不会,就像这个: http ://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html

但是,当我写了一个小程序来验证这一点时,我发现 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并在和中b声明。这是我机器上程序的结果:A.cppA.h

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动态部分。有人可以回答我的问题,或者帮助找出程序中的一些错误(如果有的话)吗?

顺便说一句,老实说,在我正在做的另一个项目中,我发现动态库和静态库中全局变量的地址是相同的。但是那个项目太大了,我不能提供一个小程序来重现这种行为。

非常感谢 !

4

1 回答 1

0

您展示的第一个命令构建了一个共享对象d.so。根据您的问题的上下文,我推测您也打算与 链接d.so,但您的第二个命令似乎缺少该部分。我假设这是一个错字,因为这是对您显示的程序输出的唯一解释——A.cpp它既直接链接到,也内置在您的d.so库中。

鉴于此,引用您链接的文章:

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

但这正是您似乎正在打破的规则,您在您的和您的主应用程序可执行文件中A两次表示该类的静态范围实例。d.so

因此,这似乎是指示的结果:“意外结果”。

于 2015-11-10T03:16:58.730 回答