2011-01-12 18 views
8

Z powodu pewnych ograniczeń jestem zmuszony do załadowania biblioteki napisanej w C w czasie wykonywania. Osoba trzecia udostępnia mi dwie biblioteki jako archiwa statyczne, które zamieniamy w obiekty wspólne. Aplikacja, z którą pracuję, ładuje jedną z bibliotek w środowisku wykonawczym na podstawie niektórych parametrów sprzętowych. Niestety jedna z bibliotek jest skonfigurowana w dużej mierze za pomocą zmiennych globalnych.dlopen i zmienne globalne w C/C++

Używam już dlsym do ładowania referencji funkcji, ale czy mogę użyć dlsym do załadowania odwołań do tych zmiennych globalnych?

Odpowiedz

10

Tak, możesz użyć dlsym, aby uzyskać dostęp do globali (o ile są one eksportowane, a nie statyczne). Poniższy przykład jest w C++ i Macu, ale oczywiście C będzie działało dobrze.

lib.cpp:

extern "C" { 
    int barleyCorn = 12; 
} 

uselib.cpp

#include <dlfcn.h> 
#include <iostream> 
using namespace std; 

main() 
{ 
    void * f = dlopen ("lib.dylib", RTLD_NOW); 
    void * obj = dlsym (f, "barleyCorn"); 
    int * ptr = (int *) obj; 
    cout << *ptr << endl; 
} 

wyjściowa:

% ./a.out 
12 
+0

Nawet jeśli wczytasz bibliotekę C++ z środowiska wykonawczego C, wszystkie obiekty globalne zostaną zbudowane! I zniszczony, gdy ją wyładujesz – yanpas

1

Tak, możesz zlokalizować każdy eksportowany symbol w bibliotece dynamicznej, używając dlsym().

1

Tak można i ja faktycznie wolą to zrobić, niż ładować funkcje. Mój standardowy model IOC robi to w ten sposób.

Wolę to, bo:

  • Obsada z void * do wskaźnika do obiektu jest technicznie bezpieczniejsze niż do wskaźnika funkcji, choć oczywiście system, który używa void * z dlsym musi umożliwiać aby przekonwertować wskaźnik. (GetProcAddress firmy Microsoft zwraca własny typ wskaźnika, co w tym przypadku wydaje mi się lepszym wyborem, ponieważ mogą zmienić rzeczywiste znaczenie tego późniejszego, jeśli zajdzie taka potrzeba).

  • Ponieważ robię to w C++, mogę wymusić, że każdy taki wyeksportowany obiekt wywodzi się ze wspólnej klasy bazowej, a następnie mogę użyć dynamic_cast z tej klasy do rzeczywistej, której oczekuję. Oznacza to, że mogę złapać błąd, jeśli nie pochodzi z późniejszej klasy, a później zapisuje błędy środowiska wykonawczego.