c++ - library - Compilación de biblioteca dinámica compartida con g++
c dynamic linking (3)
Estoy intentando compilar el siguiente código de ejemplo de biblioteca DL simple de Program-Library-HOWTO con g ++. Esto es solo un ejemplo, así puedo aprender a usar y escribir bibliotecas compartidas. El código real para la biblioteca que estoy desarrollando estará escrito en 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);
}
Si compilo el programa con gcc, funciona bien.
gcc -o foo foo.c -ldl
Cuando cambio el nombre de archivo y el compilador a la siguiente
g++ -o foo foo.cpp -ldl
Obtuve el siguiente error:
foo.cpp: 16: error: conversión inválida de ''void *'' a ''double (*) (double)''
Entiendo ( creo que entiendo, corrígeme si esto está mal) que no puedo hacer un lanzamiento implícito desde un puntero void en C ++, pero C me permite, y esta es la razón por la cual el código anterior se compilará usando gcc pero no usará g ++ Así que probé un lanzamiento explícito cambiando la línea 16 anterior a:
cosine = (double *)dlsym(handle, "cos");
Con esto en su lugar, me sale el siguiente error:
foo.cpp: 16: error: no se puede convertir "doble *" a "doble (*) (doble)" en la asignación
Es probable que estos problemas tengan más que ver con mi propio desconocimiento general de los estándares adecuados de codificación de C ++ que con cualquier otra cosa. ¿Alguien puede indicarme un buen tutorial sobre el desarrollo de bibliotecas dinámicas para Linux que utiliza el código de ejemplo de C ++?
C permite conversiones implícitas desde el void *
a cualquier tipo de puntero (incluidos los punteros de función); C ++ requiere un casting explícito. Como dice leiflundgren, debe convertir el valor de retorno de dlsym()
en el tipo de puntero de función que necesita.
Muchas personas encuentran incómoda la sintaxis del puntero a la función de C. Un patrón común es tipificar el puntero de la función:
typedef double (*cosine_func_ptr)(double);
Puede definir su cosine
variable de puntero de función como miembro de su tipo:
cosine_func_ptr cosine;
Y use el tipo de molde en lugar de la incómoda sintaxis del puntero a la función:
cosine = (cosine_func_ptr)dlsym(handle, "cos");
Con la forma en que se escribe su código, esta es realmente una pregunta en C, pero puede hacer que esto funcione en C ++. No tengo un tutorial para ti en Bibliotecas compartidas dinámicas (la página web a la que te has vinculado parece estar bien), pero aquí te explicamos cómo arreglar tu código en C ++:
declaro que my_cos es una función que (eventualmente) llamará a la función de coseno cargada dinámicamente:
double my_cos(double);
asignar el puntero de función a my_cos
my_cos = (double (*)(double)) dlsym(handle, "cos");
Esto es un poco complicado, pero está asignando a my_cos algo que devuelve un doble, es el resultado de desreferenciar a otro puntero de función, y toma un doble como argumento. Como otras personas han publicado, C ++ es un poco más exigente sobre la explicitud de su código que C.
reemplace ese mensaje de feeds algo anticuado con std :: cerr o std :: cout:
std::cerr << "error loading library cos: " << error << std::endl;
y
std::cout << "result is " << (*my_cos)(2.0)) << std::endl;
Espero que esta ayuda. Si esas cosas extrañas de casting te asustan, recomendaría Deep C Secrets de van Linden, y definitivamente el Kernighan and Ritchie Book de C.
Editar: Buen punto en el comentario sobre cómo está buscando específicamente una guía de desarrollo en C ++ en lugar de C para evitar este tipo de problema. No sé de una guía comparable en C ++, pero aproximadamente el 99% del código C se puede incrustar en el código C ++ y funciona muy bien. Este caso de puntero a función es una de las excepciones.
dlsym
devuelve un puntero al símbolo. (Como void*
ser genérico.) En su caso, debe convertirlo en un puntero a función.
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)
Entonces, este es uno de estos raros casos donde el error del compilador es una buena pista. ;)