2011-01-22 12 views
12

Estoy intentando escribir una C++ 0x envoltura alrededor dlopen()/dlsym() para cargar dinámicamente las funciones de los objetos compartidos:Almacenamiento de puntero de función en función std ::

class DynamicLoader 
{ 
    public: 
    DynamicLoader(std::string const& filename); 

    template<class Signature> 
     std::function<Signature> load(std::string const& functionName); 

    private: 
    void *itsLibraryHandle; 
}; 


DynamicLoader::DynamicLoader(std::string const& filename) 
{ 
    itsLibraryHandle = dlopen(filename.c_str(), RTLD_LAZY); 

    if(!itsLibraryHandle) 
    { /* Throw Some Error */ } 
} 

    template<class Signature> 
std::function<Signature> DynamicLoader::load(std::string const& functionName) 
{ 
    return <insert magic here> dlsym(itsHandle, functionName.c_str()); 
} 

¿Hay una manera para convertir el puntero de función void * devuelto por dlsym en una función std ::?

Respuesta

6

probar esto:

static_cast<Signature*>() 

parece obras en VC10

prueba completa:

#include <functional> 

void test() 
{} 

template <typename Signature> 
std::function<Signature> cast(void* f) 
{ 
    return static_cast<Signature*>(f); 
} 

int main() 
{ 
    std::function<void()> f = cast<void()>(&test); 
    return 0; 
} 
+0

¿Por qué envolver 'static_cast' en una función? –

+0

@NiklasR: No recuerdo exactamente, tal vez solo para demostrar cómo hacerlo de manera genérica –

+2

Tuve que usar 'reinterpret_cast' para compilarlo en Linux. – Tom

6

Sobre la base de lo que veo aquí: http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html

#include <boost/function_types/components.hpp> 
#include <boost/function_types/function_pointer.hpp> 

template< typename Signature > 
std::function<Signature> DynamicLoader::load(std::string const& name) 
{ 
    namespace ft = boost::function_types; 
    typedef typename ft::function_pointer< typename ft::components<Signature>::type >::type fp_t; 
    fp_t fun_ptr; 

    *reinterpret_cast<void**>(&fun_ptr) = dlsym(itsHandle, name.c_str()); 

    return fun_ptr; 
} 

nunca he utilizado dlsym así que no entiendo por qué el elenco se está haciendo de esa manera y no simplemente echando el regreso de dlsym así:

fun_ptr = reinterpret_cast<fp_t>(dlsym(itsHandle, name.c_str()); 
+1

No estoy seguro acerca de '' reinterpret_cast' vs static_cast' aquí (al menos en este último caso, pero aparte de que esto se ve bien –

+0

/* Escritura:. Coseno = (double (*) (double)) dlsym (handle, "cos"); parece más natural, pero el estándar C99 deja fundido desde "void *" a un puntero a función indefinido. La asignación que se utiliza a continuación es POSIX. 1-2003 (Technical Corrigendum 1) solución alternativa: consulte la explicación de la especificación POSIX de dlsym(). */From dlopen manpage –

+0

Esta solución también funciona en Unix, a diferencia del VC10. – toting

2

sólo tiene que echar resultado de dlsym() a un tipo adecuado. Aquí hay un ejemplo de trabajo completo:

#include <functional> 
#include <iostream> 
#include <stdexcept> 
#include <string> 
#include <dlfcn.h> 

class DynamicLoader 
{ 
public: 
    DynamicLoader(std::string const& filename) : 
     m_handle(dlopen(filename.c_str(), RTLD_LAZY)) 
    { 
     if (!m_handle) 
     { 
      throw std::logic_error("can't load library named \"" + filename + "\""); 
     } 
    } 

    template<class T> 
    std::function<T> load(std::string const& functionName) const 
    { 
     dlerror(); 
     void* const result = dlsym(m_handle, functionName.c_str()); 
     if (!result) 
     { 
      char* const error = dlerror(); 
      if (error) 
      { 
       throw std::logic_error("can't find symbol named \"" + functionName + "\": " + error); 
      } 
     } 

     return reinterpret_cast<T*>(result); 
    } 

private: 
    void* const m_handle; 
}; 

int main() 
{ 
    DynamicLoader const loader("/lib64/libz.so.1"); 
    auto const zlibVersion = loader.load<char const* (void)>("zlibVersion"); 
    std::cout << "zlib version: " << zlibVersion() << std::endl; 
    return 0; 
} 
+0

Comprobando! Resultado no es la forma correcta de comprobar si 'dlsym' falló. Debe verificar el valor de retorno de 'dlerror' como dice en la página man. Esto es porque 'NULL' es un valor de símbolo válido. –

+0

@MattClarkson Gracias, corregido. –

Cuestiones relacionadas