我想要完成的是在嵌入式环境中注册回调。此回调将采用以下两种形式之一:
void (*cb) (void *ctxt); or
void ClassA::VirtualFn (void);
此代码仅在使用GCC的ARM平台上运行。由于在运行时完成一些动态绑定,寄存器回调函数必须是虚拟的。上述两个函数在汇编级别上都是等效的(它们都采用单个指针)。此外,回调机制是为了性能目的而组装的,因为它发生在ISR上下文中,因此我不必担心这一点。我真正需要的是一个函数,它接受上述任何一个并存储传递的函数指针和上下文指针。即:
void isr_cb (void *ctxt) {}
gpio->RegisterIsr (isr_cb, cptr);
gpio->RegisterIsr (&ClassA::IsrHandler, this);
我已经通过将虚拟成员函数转换为 (void (*) (void *))
来测试了这一点,实际上一切都按预期工作(除了编译器警告)。
答案 0 :(得分:1)
将virtual
成员函数投射到void (*)(void *)
听起来像是一种严厉的做法。
你说:
由于在运行时完成了一些动态绑定,寄存器回调函数必须是虚拟的。
我认为你有一个ClassA
类型的对象。如果这是正确的,那么你应该:
将static
ClassA
成员注册到其签名为的回调机制:
void (*)(ClassA& ref);
添加完成实际工作的virtual
成员函数。
void doStuff();
假设注册的回调函数是:
static void foo(Class& ref);
在foo
的实施中,在doStuff
上致电ref
。
static void foo(Class& ref)
{
ref.doStuff();
}
答案 1 :(得分:0)
如果您可以在c ++ 11或std::bind
中使用boost::bind
,您将会有更轻松的时间。如果接口(即实际输出类型和实际输入参数类型相同),两者都可以让成员函数指针和自由函数相互混合,例如。
int f(double val)
{
}
class A {
int memberf(double val);
}
A instanceOfA;
auto f1 = std::bind(f, std::placeholders::_1);
auto f2 = std::bind(&A::memberf, &instanceOfA, std::placeholders::_1);
f1
和f2
现在都是采用double
并返回int
的函数,与一个是成员函数而另一个是成员函数无关自由功能,不需要演员表。我不得不承认我无法从内存中写出实际的类型。
答案 2 :(得分:0)
首先,在C和C ++中没有泛型函数指针这样的东西。
尽管如此,仍然可以采用完全一致且高性能的解决方案。
由于非成员函数已经是正确的类型,因此它是微不足道的。
如果您知道可能要传递的全部非虚拟成员函数和虚拟函数插槽,请为每个插槽定义一个简单的转发器,如下所示:
void forward_to_IsrHandler(void* p) {
((ClassA*)p)->IsrHandler();
}
gpio->RegisterIsr (forward_to_IsrHandler, (void*)this);
如果你不知道,或者真的想在表演的祭坛上牺牲标准一致性,你可以convert your member-function-pointer to a normal function-pointer (gcc extension, other compilers have their own):
void (*tmp)(ClassA*) = (void(*)(ClassA*))&ClassA::IsrHandler;
使用-Wno-pmf-conversions
删除使用扩展程序时的警告
因为对函数void(*)(void*)
和void(*)(ClassA*)
的调用在ARM上看起来完全相同,所以你可以使用它,即使它严格来说是UB:
gpio->RegisterIsr ((void(*)(void*))tmp, (void*)this);
Selectively disabling GCC warnings for only a small code-segment:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wno-pmf-conversions"
// Do the foul deed here
#pragma GCC diagnostic pop