【发布时间】:2021-01-21 07:19:46
【问题描述】:
首先,这是我的第一个问题,我通常会找到答案,如果我犯了一些错误,请见谅。
我正在尝试从动态库访问静态类的成员。问题是,我不知道为什么,这个静态类成员的内存不一样,取决于我访问它的方式。
我有一个主程序执行多项操作并调用多个动态库(使用 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 --> %p\n", 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 --> %p\n", 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)/*
【问题讨论】:
-
你读过dlopen(3) 和C++ dlopen mini howto 吗?您是否同时使用了strace(1) 和gdb(1) 来了解程序的行为?
标签: c++ static shared-libraries dlopen dynamic-library