c++ - 当我将 void 指针导入到具有指向共享对象中函数的指针的结构时,我没有收到警告

标签 c++ compilation struct shared-libraries function-pointers

昨天我正在研究共享对象的动态加载和获取函数指针。

我多次被告知,通过 void 指针共享指向函数的指针是 ISO C++ 标准禁止的,并且仍然是一个有待解决的问题。

看完Johan Petterson’s artitle “about the problem with dlsym”我更明白其中的原因,我也明白被标准禁止并不意味着你绝对不能使用它。否则,所有 C++ 程序员如何使用正确的 ISO C++ 代码使用来自共享对象的函数?只是猜测,我可能是错的,我不是 C++ 专家。

在试验我的代码时,我发现通过共享指向包含对我要调用的函数的引用的结构的指针,我的编译器不会报错。我在编译时使用 -Wall 和 -pedantic。

我的代码如下所示:

myclass.hpp

class myclass
{
    public:
    virtual void dosomething (void)=0;
}

api.hpp

#include <myclass.hpp>
struct API
{
    myclass* (* func)(void);
};

so.hpp

#include <iostream>
#include "myclass.cpp"
#include "api.hpp"

class childclass : public myclass
{
    void dosomething (void)
    {
        std::cout << "Did it.\n";
    }
}

/* function to return a new instance of childclass */

extern "C" myclass* make (void)
{
    return new childclass;
}

/* struct that contains a pointer to the function */

extern "C" API interface;
API interface
{
    make
};

host.cpp

#include <iostream>
#include <dlfcn.h>
#include "myclass.hpp"
#include "api.hpp"
int main (void)
{
    void * th = dlopen("./so.so", RTLD_LAZY);
    /* error checking was here */

    #ifndef usefunction

        API* api = static_cast<API*>( dlsym(th, "interface") );
        myclass * inst = api->make();
        inst->dosomething();

    #else

        myclass* (*func)(void) = reinterpret_cast<myclass* (*)(void)>( dlsym(th, "make") );
        /* will never get to this point */

    #endif

    return 0;
}

已经编译了 so.so,然后我编译了我的 host.cpp 文件。

g++ -ldl -Wall -pedantic host.cpp -o host 编译正常,程序正确打印 Did it. 运行时。

g++ -ldl -Wall -pedantic host.cpp -o host -Dusefunction 提示

In function ‘int main(int, char**)’:
warning: ISO C++ forbids casting between pointer-to-function
and pointer-to-object [enabled by default]

我知道这只是一个警告,但为什么在第一种情况下不打印警告,当使用结构时,如果最终我能够间接引用指向驻留在共享对象中的函数的指针?

说到这里,有人知道以完全正确的 ISO C++ 方式实现所有这些的方法吗?它甚至存在吗?

最佳答案

完全符合标准的解决方案:

extern "C" typedef int (func_t)(char, double); // desired API function signature

int main()
{
    static_assert(sizeof(void *) == sizeof(func_t *), "pointer cast impossible");

    void       *  p = dlsym(handle, "magic_function");
    char const * cp = reinterpret_cast<char const *>(&p);

    func_t     * fp;

    std::copy(cp, cp + sizeof p, reinterpret_cast<char *>(&fp));

    return fp('a', 1.25);
}

一种更简单但更可疑的写法,使用了一些类型双关语:

static_assert(sizeof(void *) == sizeof(func_t *), "pointer cast impossible");

void   * vp = dlsym(handle, "magic_function");
func_t * fp;

*reinterpret_cast<void **>(&fp) = vp;  // this is type-punning

关于c++ - 当我将 void 指针导入到具有指向共享对象中函数的指针的结构时,我没有收到警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12585030/

相关文章:

c++ - 使用为不同机器编译的静态库

C++指针疑惑

将结构的内容复制到另一个

c++ - Qt Creator,Mac OS X : Error: "Symbol(s) not found" when calling function from included header

链接静态库时编译 CUDA 代码

opengl - 代码::阻止对 "*"的 undefined reference

c - 通过计算成员的大小来测量结构的大小

c++ - qt 5.0.1 mingw 32位问题

c++ - 类封装在命名空间后,友元函数无法再访问类的私有(private)数据成员

c++ - 如何使用 boost::format 对变量中包含小数位数的数字进行零填充?