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

Mar*_*rio 7 c++ struct compilation function-pointers shared-libraries

昨天我正在研究动态加载共享对象以及获取函数指针.

我多次被告知,ISO C++标准禁止通过void指针共享指向函数的指针,并且仍然需要解决问题.

在阅读了Johan Petterson的文章"关于dlsym的问题"后,我更了解原因,并且我也明白被标准禁止并不意味着你绝对不能使用它.否则,所有C++程序员如何使用具有正确ISO C++代码的共享对象的函数?只是猜测,我可能是错的,我不是很熟悉C++.

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

我的代码如下:

myclass.hpp

class myclass
{
    public:
    virtual void dosomething (void)=0;
}
Run Code Online (Sandbox Code Playgroud)

api.hpp

#include <myclass.hpp>
struct API
{
    myclass* (* func)(void);
};
Run Code Online (Sandbox Code Playgroud)

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
};
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

已经编译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]
Run Code Online (Sandbox Code Playgroud)

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

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

Vau*_*ato 0

如果您将函数指针封装在结构中,那么您可以通过添加额外的间接级别来解决该问题。想象一下,如果一个函数指针占用 10 个字节,但一个对象指针占用 4 个字节。您的结构体至少有 10 个字节,并且您将有一个指向该结构体的 4 字节指针。这一切都很好。当您访问该结构体以获取函数指针时,您将提取完整的 10 个字节。什么都没有丢失。但是,如果要将 10 字节函数指针转换为 4 字节对象指针,则必然会丢失 6 字节信息。

这在这里不是一个实际问题,因为支持 dlsym 的平台必须具有足够大的 void 指针来存储函数指针的地址,但编译器试图阻止您编写不可移植的代码。