Динамическая компиляция общей библиотеки с помощью g++

Я пытаюсь скомпилировать следующий простой пример кода библиотеки DL из программа-библиотека-HOWTO С g++. Это просто пример, чтобы я мог научиться использовать и писать общие библиотеки. Реальный код для библиотеки, которую я разрабатываю, будет написан на C++.

#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 ("%fn", (*cosine)(2.0));
    dlclose(handle);
}

если я компилирую программу с gcc, она работает нормально.

gcc -o foo foo.c -ldl

когда я изменяю имя файла и компилятор на следующий

g++ -o foo foo.cpp -ldl

Я получаю следующее ошибка:

фу.cpp: 16: ошибка: недопустимое преобразование из "void*" в " double (*)(double)"

Я понимаю (я думаю я понимаю, поправьте меня, если это неправильно) , что я не могу сделать неявное приведение из Указателя void в C++, но C позволяет мне, и поэтому приведенный выше код будет компилироваться с помощью gcc, но не с помощью g++. Поэтому я попробовал явный бросок, изменив строку 16 выше на:

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

С этим на месте, я получаю следующее ошибка:

фу.cpp: 16: ошибка: не удается преобразовать "double*" в "double (*) (double)" в присваивании

эти проблемы, вероятно, больше связаны с моим общим незнанием надлежащих стандартов кодирования c++, чем что-либо еще. Может ли кто-нибудь указать мне хороший учебник по разработке динамических библиотек для Linux, использующих пример кода C++?

3 ответов


C допускает неявные преобразования от void * для любого типа указателя (включая указатели функций); C++ требует явного приведения. Как говорит лейфлундгрен, вам нужно привести возвращаемое значение dlsym() к типу указателя функции, который вам нужен.

многие люди находят синтаксис указателя функции C неудобным. Одним из распространенных шаблонов является typedef указатель функции:

typedef double (*cosine_func_ptr)(double);

вы можете определить переменную указателя функции cosine как член вашего тип:

cosine_func_ptr cosine;

и приведение с использованием типа вместо неудобного синтаксиса указателя функции:

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

dlsym возвращает указатель на символ. (As void* быть общим.) В вашем случае вы должны привести его к функции-указателю.

 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)

Итак, это один из тех редких случаев, когда ошибка компилятора является хорошей подсказкой. ;)


С тем, как ваш код, если он написан, это действительно больше вопрос C, но вы можете заставить это работать на C++. У меня нет учебника для вас по динамическим общим библиотекам (веб-страница, на которую вы ссылаетесь, кажется прекрасной), но вот как исправить ваш код на C++:

  • объявите my_cos функцией, которая (в конечном итоге) вызовет динамически загруженную косинусную функцию:

    double my_cos(double);
    
  • присвоить указатель на функцию с my_cos

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

Это немного сложно, но он назначает my_cos что-то, что возвращает double, является результатом разыменования другого указателя функции и принимает double в качестве аргумента. Как и другие люди, c++ немного более требователен к эксплицитности вашего кода, чем C.

  • замените это довольно датированное сообщение fputs на std:: cerr или std:: cout:

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

и

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

надеюсь, что это поможет. Если эта странная касти пугает вас, я бы рекомендовал Deep C Secrets Ван Линдена и, безусловно, книгу Кернигана и Ричи о C.

Edit: хороший момент в комментарии о том, как вы специально ищете руководство по разработке на C++, а не C, чтобы избежать этого типа проблемы. Я не знаю сопоставимого руководства на C++, но около 99% кода C может быть встроено в C++ код и работа просто отлично. Этот случай указателя функции является одним из исключений.