0

I'm trying to load a shared object (SensorTemp derived class) at runtime using the dlopen() API. When I try to static-case the pointer to the appropriate function pointer, I get

LinkTest.cpp:26:48: error: invalid static_cast from type ‘void*’ to type ‘Sensor*()’
Sensor* mySensor = static_cast<Sensor *()>(mkr)(myHub, a, b, c, d, e);

Here's the relevant Sensor.h base class constructor:

class Sensor
{
public:
    Sensor(Hub& _pHub, const std::string& _name, const std::string& _type, const std::string& _logLevel, const std::string& _configInfo, const std::string& _location): m_pHub(&_pHub), m_name(_name), m_type(_type), m_logLevel(_logLevel), m_configInfo(_configInfo), m_location(_location) {}

Derived class SensorTemp.h : (its CTOR calls the base CTOR)

#include "Sensor.h"

class SensorTemp : public Sensor
{
public:
    SensorTemp(Hub& _pHub,  const std::string& _name, 
                            const std::string& _type, 
                            const std::string& _logLevel, 
                            const std::string& _configInfo, 
                            const std::string& _location);
    ~SensorTemp() {}
    void* Run();
private:
    int m_lowTemp;
    int m_highTemp;
    int m_interval;
};

extern "C"
{
    SensorTemp* Create(Hub& _pHub,  const std::string& _name, 
                                    const std::string& _type, 
                                    const std::string& _logLevel, 
                                    const std::string& _configInfo, 
                                    const std::string& _location)
    {
        return new SensorTemp(_pHub, _name, _type, _logLevel, _configInfo, _location);
    }

}

#endif //__SENSORTEMP_H__

the test:

int main(int argc, char **argv)
{
    Hub myHub;
    string a = "A";
    string b = "B";
    string c = "C";
    string d = "D";
    string e = "E";
    string f = "F";
    void *hndl = dlopen("./libSensorTemp.so", RTLD_LAZY);
    if(hndl == NULL)
    {
       std::cerr << dlerror() << std::endl;
       exit(-1);
    }
    void *mkr = (Sensor*)dlsym(hndl, "Create");
    Sensor* mySensor = static_cast<Sensor *()>(mkr)(myHub, a, b, c, d, e);
    mySensor->Run();

}
susdu
  • 852
  • 9
  • 22
  • 1
    Have a look at [this question](http://stackoverflow.com/questions/1096341/function-pointers-casting-in-c). – Dan Mašek Mar 20 '16 at 14:46

2 Answers2

1

Your cast to a pointer to function is wrong. Your code should be:

void *mkr = (void *)dlsym(hndl, "Create"); // only the address matters here
Sensor* mySensor = static_cast<Sensor *(*)(Hub&, const std::string&, const std::string&,
    const std::string&, const std::string&, const std::string&)>(mkr)(myHub, a, b, c, d, e);
mySensor->Run();

Because you want to cast mkr to a pointer to a function taking one Hub reference and 5 string references and returning a pointer to Sensor

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • `LinkTest.cpp:27:69: error: invalid static_cast from type ‘void*’ to type ‘Sensor* (*)(Hub&, const string&, const string&, const string&, const string&, const string&) {aka Sensor* (*)(Hub&, const std::basic_string&, const std::basic_string&, const std::basic_string&, const std::basic_string&, const std::basic_string&)}’ const std::string&, const std::string&, const std::string&)>(mkr)(myHub, a, b, c, d, e);` – susdu Mar 20 '16 at 14:58
  • What compiler do you use? I cannot reproduce the error. I tested my code with MSVC2008 express... – Serge Ballesta Mar 20 '16 at 15:52
  • I use gcc, but if it's compiler depedent it's probably not the best approach – susdu Mar 20 '16 at 18:18
1

In reference to this question, here is a simplified example:

#include <dlfcn.h>
#include <string>

class Sensor;
class Hub;

extern "C"
{
    Sensor* Create(Hub& _pHub
        , const std::string& _name
        , const std::string& _type
        , const std::string& _logLevel
        , const std::string& _configInfo
        , const std::string& _location)
    {
        return nullptr;
    }
}



int main(int argc, char **argv)
{
    void *hndl = dlopen("./libSensorTemp.so", RTLD_LAZY);
    if(hndl == NULL) {
       exit(-1);
    }

    void *mkr = (Sensor*)dlsym(hndl, "Create");

    typedef Sensor*(*create_fn)(Hub&
        , const std::string&
        , const std::string&
        , const std::string&
        , const std::string&
        , const std::string&);

    create_fn creator = 0;
    *reinterpret_cast<void**>(&creator) = mkr;

    // ....
}
Community
  • 1
  • 1
Dan Mašek
  • 17,852
  • 6
  • 57
  • 85
  • Thanks! I read the reference but can't understand the logic behind the last two lines: why the = 0? and why reinterpreting as void** ? isn't the purpose to convert a void pointer to a function pointer? – susdu Mar 20 '16 at 15:54
  • 1
    The `= 0` is so we have the function pointer variable initialized to some sensible value. The reason for the `void**` is that you can't convert function pointer to object pointer directly. However, a pointer to a function pointer (i.e. `create_fn*`) **is** an object pointer. So is `void**`. Hence, we can convert between the two. So with `*reinterpret_cast(&creator)` we reinterpret creator as a `void*` and the assignment is valid. – Dan Mašek Mar 20 '16 at 16:08
  • The problem now is `./libSensorTemp.so: undefined symbol: _ZTI6Sensor`. When the derived class CTOR calls the base one, the base CTOR's name is mangled and it can't resolve it. – susdu Mar 20 '16 at 17:07
  • @susdu Better start a new question for that. – Dan Mašek Mar 20 '16 at 17:21