2009-01-27 14 views
11

Próbuję skompilować następujący prosty przykładowy kod biblioteki DL z Program-Library-HOWTO z g ++. To tylko przykład, więc mogę się nauczyć obsługiwać i pisać biblioteki współdzielone. Prawdziwy kod biblioteki, którą tworzę, będzie napisany w C++.Kompilacja dynamicznej biblioteki współdzielonej za pomocą g ++

#include <stdlib.h> 
#include <stdio.h> 
#include <dlfcn.h> 

int main(int argc, char **argv) { 
    void *handle; 
    double (*cosine)(double); 
    char *error; 

    handle = dlopen ("/lib/libm.so.6", RTLD_LAZY); 
    if (!handle) { 
     fputs (dlerror(), stderr); 
     exit(1); 
    } 

    cosine = dlsym(handle, "cos"); 
    if ((error = dlerror()) != NULL) { 
     fputs(error, stderr); 
     exit(1); 
    } 

    printf ("%f\n", (*cosine)(2.0)); 
    dlclose(handle); 
} 

Jeśli skompiluję program z gcc, działa dobrze.

gcc -o foo foo.c -ldl 

Kiedy zmienić nazwę pliku i kompilator następującym

g++ -o foo foo.cpp -ldl 

pojawia się następujący błąd:

foo.cpp:16: error: invalid conversion from 'void*' to 'double (*)(double)'

rozumiem (myślę Rozumiem, poprawcie mnie jeśli to jest złe), że nie mogę wykonać niejawnego rzutowania z pustego wskaźnika w C++, ale C pozwala mi, i to dlatego powyższy kod skompiluje używając gcc, ale nie użyje g g ++. Spróbowałem więc wyraźne obsady zmieniając linię 16 powyżej:

cosine = (double *)dlsym(handle, "cos"); 

Mając to na miejscu, pojawia się następujący błąd: prawdopodobnie

foo.cpp:16: error: cannot convert 'double*' to 'double (*)(double)' in assignment

Te problemy mają więcej wspólnego z moim ogólnym ignorancji prawidłowych standardów kodowania w C++ niż cokolwiek innego. Czy ktoś może wskazać mi dobry tutorial na temat tworzenia dynamicznych bibliotek dla Linuksa, który używa przykładowego kodu C++?

+0

Proponuję przejście przez "Myślenie w C++", aby przyspieszyć działanie C++. Jak poprawnie zauważyłeś, nie możesz niejawnie rzucić z void * na inne wskaźniki w C++, co sugeruje, że naprawdę potrzebujesz tylko przyspieszyć działanie C++, a nie innych obszarów :) – workmad3

+0

Dzięki, czytam C++ Primer w wolnym czasie, ale teraz mam już należny projekt. –

Odpowiedz

24

C pozwala na niejawne rzuty z void * na dowolny typ wskaźnika (w tym wskaźniki funkcji); C++ wymaga jawnego przesyłania. Jak mówi leiflundgren, musisz odrzucić wartość zwracaną przez dlsym() do potrzebnego typu wskaźnika funkcji.

Wiele osób uważa, że ​​składnia wskaźnika funkcji C jest niezręczna. Jeden wspólny wzór jest typedef wskaźnik funkcji:

typedef double (*cosine_func_ptr)(double); 

można zdefiniować funkcję wskaźnika zmiennej cosine jako członek typu:

cosine_func_ptr cosine; 

i odlewane przy użyciu typu zamiast niewygodnej wskaźnika funkcji składnia:

cosine = (cosine_func_ptr)dlsym(handle, "cos"); 
+0

Nie mogę przestać myśleć, że musiałaś przeczytać moje myśli, aby dowiedzieć się, jaki był mój prawdziwy problem. Dziękuję Ci. :) –

+5

Używaj reinterpret_cast () zamiast operatora C cast. –

9

dlsym zwraca wskaźnik do symbolu. (Jako void* być ogólna.) W twoim przypadku powinieneś rzucić go na wskaźnik funkcji.

double (*mycosine)(double); // declare function pointer 
mycosine = (double (*)(double)) dlsym(handle, "cos"); // cast to function pointer and assign 

double one = mycosine(0.0); // cos(0) 

Więc to jeden z tych rzadkich przypadkach, gdy błąd kompilator jest dobry trop. ;)

+0

Twoja deklaracja wskaźnika funkcji nie jest. – Arkadiy

+0

Działa to z podwójnym (* cosinus) (podwójne); z oryginalnego kodu, ale nie z deklaracją wskaźnika funkcji, którą podałeś. Ponieważ jestem ignorantem, który zadaje tu pytania, nie uważam, że powinienem zmienić kod. :) –

0

z okazji kodzie jeśli pisemnej, to jest naprawdę bardziej C pytanie, ale można uzyskać to będzie działać w C++.Nie mam poradnik dla Ciebie dynamicznych bibliotek współdzielonych (strony internetowej związanej wydaje się w porządku), ale oto jak naprawić swój kod w C++:

  • zadeklarować my_cos się funkcję, która będzie (ostatecznie) wywołać dynamicznie załadowanego funkcję cosinus:

    double my_cos(double); 
    
  • przypisać wskaźnik funkcji do my_cos

    my_cos = (double (*)(double)) dlsym(handle, "cos"); 
    

Jest to trochę skomplikowane, ale przypisuje ono my_cos coś, co zwraca podwójne, jest wynikiem dereferencji innego wskaźnika funkcji i przyjmuje podwójne jako argument. Jak inni napisali, C++ jest trochę bardziej wymagający o jednoznaczności w kodzie niż C.

  • zastąpić że raczej stary wiadomość fputs z std :: cerr lub std :: cout:

    std::cerr << "error loading library cos: " << error << std::endl; 
    

i

std::cout << "result is " << (*my_cos)(2.0)) << std::endl; 

nadzieję, że ta pomoc. Jeśli to dziwne, kastowe rzeczy cię przerażają, polecam Deep C Secrets van Lindena, a na pewno Kernighana i Ritchie Book na temat C.

Edytuj: Dobrze trafiłeś w komentarz o tym, jak konkretnie szukasz rozwoju przewodnik w C++ zamiast C, aby uniknąć tego typu problemów. Nie znam porównywalnego przewodnika w C++, ale około 99% kodu C może być osadzone w kodzie C++ i działa dobrze. Ten wskaźnik wskaźnika funkcji jest jednym z wyjątków.

+0

Podany przykładowy kod to C, ale będę rozwijał się w C++, więc muszę skompilować za pomocą g ++. Pytanie może być naiwne, a odpowiedź brzmi: "Nie kompiluj kodu C za pomocą g ++". :) –

Powiązane problemy