Динамическая компиляция совместно используемой библиотеки с g ++ - PullRequest
12 голосов
/ 27 января 2009

Я пытаюсь скомпилировать следующий простой пример кода библиотеки DL из Program-Library-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 ("%f\n", (*cosine)(2.0));
    dlclose(handle);
}

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

gcc -o foo foo.c -ldl

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

g++ -o foo foo.cpp -ldl

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

foo.cpp: 16: ошибка: неверное преобразование из 'void *' в 'double (*) (double)'

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

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

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

foo.cpp: 16: ошибка: невозможно преобразовать 'double *' в 'double (*) (double)' в присваивании

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

Ответы [ 4 ]

26 голосов
/ 27 января 2009

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

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

typedef double (*cosine_func_ptr)(double);

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

cosine_func_ptr cosine;

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

cosine = (cosine_func_ptr)dlsym(handle, "cos");
9 голосов
/ 27 января 2009

dlsym возвращает указатель на символ. (Как 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)

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

0 голосов
/ 08 февраля 2019

В C ++ вы должны выполнить reinterpret_cast (не приведение C):

typedef double (* double_from_double_function_t(double));
…
double_from_double_function_t cosine = reinterpret_cast<double_from_double_function_t>(dlsym(handle, "cos"));
0 голосов
/ 27 января 2009

То, как ваш код написан, на самом деле это больше вопрос 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;

Надеюсь, что это поможет. Если вас пугает эта странная вещь, я бы порекомендовал «Глубокие секреты С» Ван Линдена и определенно книгу Кернигана и Ричи на C.

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

...