C兼容的C++回调

C-compatible C++ callbacks

本文关键字:C++ 回调      更新时间:2023-10-16

考虑一个以回调函数(指针)为参数的库函数。如果使用了正则函数指针,则该函数可以与正则C和C++函数一起使用,但不能使用任何类方法:

typedef void(*CALLBACK_T)(int);
void testCallback(CALLBACK_T cb){
    cb(5);
}
void intOut(int i){
    std::cout << i << std::endl;
}
class Test{
public:
    void intOut2(int i){
        std::cout << "Test: " << i << std::endl;
    }
};
void test(void){
    testCallback(&intOut);
    Test t;
    testCallback(&t.intOut2); //won't work
}

我可以使用std::function来封装类成员,但这会破坏C的兼容性。

我能想到的唯一选项是创建一个指向回调处理程序的附加上下文指针:

typedef void(*CALLBACK2_T)(int, void*);
void testCallback2(CALLBACK2_T cb, void* context){
    cb(5, context);
}

但这也需要跟踪上下文信息(回调不会在库函数中直接调用)。

你知道如何将回调同时用于C函数和C++类成员吗?

您在这里几乎没有回旋余地。绝大多数情况下,最常用的方法是使用额外的上下文指针。

一个可行的替代方案是在运行时创建一个thunk。也就是说,分配一些内存并将其标记为可执行文件。然后,内存包含调用成员函数所需的指令。调用的主体,对象实例,位于相对于thunk的固定偏移处。这是一项相当肮脏的工作,而且不完全是可移植的。我不推荐。

Imho别无选择。

如果您不想跟踪库中的上下文,则无法获取指向回调函数的"this"指针。您正在迫使库的使用者使用全局变量,这是非常有限的。

等价于测试::intOut2()的C是:

intOut2(Test *this, int i)

所以&t.intOut2没有正确的类型作为CALLBACK_t。

它应该通过将intOut2指定为static:来工作

class Test{
public:
     static void intOut2(int i){
        std::cout << "Test: " << i << std::endl;
    }
};