2009-01-27 33 views
11

Estoy intentando compilar el siguiente código de ejemplo de biblioteca DL simple desde 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++.Compilación de biblioteca dinámica compartida con 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); 
} 

Si puedo compilar el programa con gcc que trabaja muy bien.

gcc -o foo foo.c -ldl 

Cuando se cambia el nombre de archivo y compilador para el siguiente

g++ -o foo foo.cpp -ldl 

me sale el siguiente error:

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

entiendo (I piensan 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 usin g g ++. Así que he intentado una conversión explícita al cambiar la línea 16 arriba a:

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

Con esto en su lugar, me sale el siguiente error:

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

Estos problemas probablemente tienen más que ver con mi propia ignorancia general de los estándares de codificación C++ adecuados más que 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++?

+0

Sugiero pasar por 'Pensar en C++' para ponerte al día con C++. Como correctamente detectó, no puede convertir implícitamente void * a otros punteros en C++, y eso implica que realmente solo necesita ponerse al día con C++ en lugar de las otras áreas :) – workmad3

+0

Gracias, estoy leyendo C++ Primer en mi tiempo libre, pero ahora tengo un proyecto pendiente. –

Respuesta

24

C permite conversiones implícitas desde void * a cualquier tipo de puntero (incluidos los punteros a las funciones); C++ requiere un casting explícito. Como dice leiflundgren, debe convertir el valor de retorno de dlsym() en el tipo de puntero a 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 typedef la función de puntero:

typedef double (*cosine_func_ptr)(double); 

puede definir su función variable de puntero cosine como un miembro de su tipo:

cosine_func_ptr cosine; 

y fundido utilizando el tipo de cambio del puntero de función incómoda sintaxis:

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

No puedo evitar pensar que tenía que leer mi mente para descubrir cuál era mi verdadero problema. Gracias. :) –

+5

Utilice reinterpret_cast () en lugar del operador de colada en C. –

9

dlsym devuelve un puntero al símbolo. (Como void* para 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) 

Este es uno de estos raros casos en los que el error del compilador es una buena pista. ;)

+0

La declaración del puntero a la función no es. – Arkadiy

+0

Esto funciona con doble (* coseno) (doble); desde el código original, pero no con la declaración del puntero a la función que proporcionó. Como soy el ignorante que hace preguntas aquí, no creo que deba cambiar tu código. :) –

0

con la forma en que su código si escrito, esto es realmente más de una pregunta C, pero se puede conseguir que esto funcionará en C++.No tengo un tutorial para usted en bibliotecas compartidas dinámicas (la página web se ha vinculado a parece muy bien), pero aquí es cómo solucionar su código en C++:

  • declaran my_cos ser una función que (con el tiempo) llamar a la función coseno de carga dinámica:

    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 le 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 exigentes en cuanto a lo explícito de su código de C.

  • reemplazar ese mensaje fputs bastante anticuado con un 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; 

la esperanza de que esta ayuda. Si eso te asusta Casty raro, me gustaría recomendar profundo C Secretos de Van Linden, y sin duda el Kernighan y Ritchie libro sobre C.

Editar: Buen punto en el comentario acerca de cómo se está buscando específicamente para un desarrollo guía 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 código C++ y funciona muy bien. Este caso de puntero a función es una de las excepciones.

+0

El código de ejemplo proporcionado es C, pero lo desarrollaré en C++, por lo que debo compilar con g ++. La pregunta puede ser ingenua, y la respuesta podría ser "No compilar el código C con g ++". :) –

Cuestiones relacionadas