通过C++中的非静态函数设置对C函数指针的回调

Setting up callback to C function pointer via non-static function in C++

本文关键字:函数 指针 回调 静态函数 C++ 通过 设置      更新时间:2023-10-16

感兴趣的C标头(some_external_library.h)声明以下struct,其中包含一个函数指针:

#ifdef __cplusplus
extern "C" {
#endif
    typedef struct {
        void (*function_ptr)(void);
    } fp_test;
    /* ... */
#ifdef __cplusplus
}
#endif

some_external_library.c中发生一些有趣的事件时,会调用此函数指针。

我想在一个名为Foo的C++class的实例中设置一个指向该struct实例的指针,然后将function_ptr的值设置为具有Foo实例的非静态函数的地址。换句话说,我希望我的C++代码定义这个函数指针的作用。

例如,这里有一个类声明(foo.h):

class Foo {
    public:
        fp_test *fp_test_ptr;
        void setup(void);
        void breakdown(void);
        void my_callback(void);
};

有三个函数:一个用于初始化值的setup函数,一个用于释放任何指针或对象的breakdown函数,以及一个不接受和返回任何参数的简单my_callback函数。

以下是类定义(foo.cpp):

int main(int argc, char** argv) {
    Foo some_foo;
    some_foo.setup();
    some_foo.breakdown();
    return EXIT_SUCCESS;
}
void Foo::setup(void) {
    fp_test_ptr = new fp_test;
    fp_test_ptr->function_ptr = &Foo::my_callback;
}
void Foo::breakdown(void) {
    delete fp_test_ptr;
}
void Foo::my_callback(void) {
    std::fprintf(stderr, "Callback called...n");
}

当我编译这个时,我得到以下错误:

foo.h:: error: assigning to 'void (*)()' from incompatible type 'void (Foo::*)()'
fp_test_ptr->function_ptr = &Foo::my_callback;
                          ^------------------

我尝试强制转换此调用,但收到一条错误消息,指示我无法从类型void (Foo::*)()强制转换为void (*)()

我如何在C++中设置一个非静态方法作为C库的函数指针?

我能够获得Foo::my_callback()static版本进行编译,但我认为我不能使用静态方法来满足我的需求,因为我不能访问类实例some_foo中非全局成员的状态,只能访问全局成员的值。

有没有一种方法可以用非静态函数来实现这一点?

解决这一问题的正常方法是拥有两个一函数:一个静态函数和一个成员函数,并将对象实例作为参数传递

class Foo {
public:
    fp_test *fp_test_ptr;
    void setup();
    void breakdown();
    void my_callback();
    static void _my_callback(void* self);
};
void Foo::_my_callback(void* self)
{
    reinterpret_cast<Foo*>(self)->my_callback();
}

将函数指针的C签名更改为

void (*function_ptr)(void*)

调用它时,将对象实例作为参数传递。

编辑:要从C调用,大概你需要知道它指的是哪个对象,所以不知何故,你需要一种将C++实例传递给C的方法。

Foo* fu1 = new Foo();
Foo* fu2 = new Foo();
/* fu1 and fu2 need to be passed to the C program */
...
/* Setting up */
fp_test pointerTest;
pointerTest.function_ptr = Foo::_my_callback;
...
/* Calling */
pointerTest.function_ptr(fu1);
pointerTest.function_ptr(fu2);

这是不可能的。每个非静态c++成员函数都有一个隐藏的"this*"参数。所以函数签名总是不同的。