访问c++中动态库中的静态类成员



首先,这是我的第一个问题,我通常会找到答案,所以如果我犯了一些错误,很抱歉。

我正试图从动态库访问一个静态类的成员。问题是,我不知道为什么,这个静态类成员的内存不一样,这取决于我如何访问它

我有一个执行多项任务并调用多个动态库的主程序(使用dlopen/dlsym(。这些动态库应该访问属于主程序的一些变量。如果这些变量不是静态的,我可以共享一个指针,所以我对这些变量没有问题。但是,当这些变量是静态的时,我发现了一些问题。

我在linux下运行这个程序,使用g++7.5.0和glibc 2.27。

这是一个小例子,展示了我遇到的问题:主程序main.cpp修改静态变量value并调用动态库libShare.so来创建ShareDerived对象。此对象访问静态变量value以打印它。

/*** Main.cpp ***/
#include <dlfcn.h>
#include "ShareBase.hpp"
int StaticClass::value = 1;
int main() {
StaticClass::value = 3;
void* hdl = dlopen("./lib/libShare.so", RTLD_LAZY | RTLD_GLOBAL);
ShareBase*(*obj)() = (ShareBase*(*)())dlsym(hdl,"createObject");
obj()->BaseValue();
obj()->DerivedValue();
delete (obj());
dlclose(hdl);
return 0;
}
/*** ShareBase.hpp ***/
#pragma once
class StaticClass {
public:
StaticClass() = delete;
~StaticClass() = delete;
static int value;
};
class ShareBase {
public:
ShareBase();
virtual ~ShareBase();
void BaseValue();
virtual void DerivedValue() = 0;
};
/*** ShareBase.cpp ***/
#include "ShareBase.hpp"
#include <stdio.h>
ShareBase::ShareBase() {}
ShareBase::~ShareBase() {}
void ShareBase::BaseValue() {
printf("Base: %d --> %pn", StaticClass::value, (void*)&StaticClass::value);
}
/*** ShareDerived.hpp ***/
#pragma once
#include "ShareBase.hpp"
class ShareDerived:public ShareBase {
public:
ShareDerived();
virtual ~ShareDerived();
void DerivedValue();
};
extern "C" {
ShareBase* createObject() {
auto *m = new ShareDerived();
return (ShareBase*)m;
}
}
/*** ShareDerived.cpp ***/
#include "ShareDerived.hpp"
#include <stdio.h>
ShareDerived::ShareDerived() {}
ShareDerived::~ShareDerived() {}
void ShareDerived::DerivedValue() {
printf("Derived: %d --> %pn", StaticClass::value, (void*)&StaticClass::value);
printf("Derived: ");
BaseValue();
}

这是我用来编译这个例子的makefile:

CXX         := g++
CXX_FLAGS   := -Wall -Wextra -std=c++17 -ggdb
BIN         := bin
SRC         := src
INC         := include
LIB         := lib
EXE         := test
all: main lib
main: $(BIN)/$(EXE)
ar rcs $(LIB)/libMain.a $(BIN)/Main.o $(BIN)/ShareBase.o
lib: $(LIB)/libShare.so
$(BIN)/$(EXE): $(BIN)/Main.o $(BIN)/ShareBase.o
$(CXX) $(CXX_FLAGS) -I$(INC) -L$(LIB) $^ -o $@ -ldl
$(LIB)/libShare.so: $(BIN)/ShareDerived.o
$(CXX) $(CXX_FLAGS) -I$(INC) -L$(LIB) -shared $^ -o $@ -lMain
$(BIN)/%.o: $(SRC)/%.cpp
$(CXX) $(CXX_FLAGS) -I$(INC) -L$(LIB) -fPIC -c -o $@ $<
clean:
-rm $(BIN)/* $(LIB)/*

这就是我得到的输出:

Base: 3 --> 0x55e8df87f010 <-- Calling base function from main, static member value is OK.
Derived: 1 --> 0x7f40b5918090 <-- Why this value (and pointer) is not the same as previous one?
Derived: Base: 1 --> 0x7f40b5918090 <-- Accessing to this value calling Base function from Derived class is neither OK.

那么,我的错在哪里呢?我能做这个吗?为什么行为会因您访问静态成员的方式而异?使用相同的指针,调用任何派生类函数时,静态变量的值是在调用main之前保存的值。但是,在调用基函数时,静态变量的值是您在执行过程中修改的值。

如果问题是概念性的;我如何让一个主程序执行多项任务并调用需要访问一些主程序变量的动态库?

这是我的第一篇帖子,所以可能还不清楚。在这种情况下,请告诉我,我会编辑,让它更清楚。

编辑:之后,@sam回答,我修改了makefile,现在它按预期工作

CXX         := g++
CXX_FLAGS   := -Wall -Wextra -std=c++17 -ggdb
BIN         := bin
SRC         := src
INC         := include
LIB         := lib
EXE         := test
all: main lib exec
exec: $(BIN)/$(EXE)
main: $(LIB)/libMain.so
lib: $(LIB)/libShare.so
$(BIN)/$(EXE): $(BIN)/Main.o
$(CXX) $(CXX_FLAGS) -I$(INC) -L$(LIB) -Wl,-rpath,$(LIB) $^ -o $@ -ldl -lMain
$(LIB)/libMain.so: $(BIN)/ShareBase.o
$(CXX) $(CXX_FLAGS) -I$(INC) -L$(LIB) -shared $^ -o $@
$(LIB)/libShare.so: $(BIN)/ShareDerived.o
$(CXX) $(CXX_FLAGS) -I$(INC) -L$(LIB) -Wl,-rpath,$(LIB) -shared $^ -o $@ -lMain
$(BIN)/%.o: $(SRC)/%.cpp
$(CXX) $(CXX_FLAGS) -I$(INC) -L$(LIB) -fPIC -c -o $@ $<
clean:
-rm $(BIN)/* $(LIB)/*
$(CXX) $(CXX_FLAGS) -I$(INC) -L$(LIB) -shared $^ -o $@ -lMain

您正在将Main.cpp直接链接到共享库中。

并且您正在将Main.cpp作为可执行文件的一部分运行。

因此,存在静态类成员的重复实例化。这违反了"一个定义规则",并导致未定义的行为。这是对你观察到的行为的解释。

您之所以这么做,很可能是因为没有链接-lMain,所显示的程序会出现segfault。发生这种情况的原因完全无关——内联的C链接函数从未在共享库中实例化,因为编译器在编译共享库时没有理由实例化它。您可能不知道为什么,但发现链接Main解决了segfault,但导致了这种行为。这是一个经典的XY问题。你的问题本来应该是你为什么会出现segfault。

相关内容

  • 没有找到相关文章

最新更新