如何为不支持类实例的C API编写一个C++包装器?

5

在一个我们打算用C++编写的项目中,我们使用了一个C库。这个C库提供了一些函数来注册回调函数,每次中断时都会调用它们。我们在构造函数中注册我们的回调函数。因此,我们基本上有以下(简化后的)结构:

OurClass::OurClass() {
  //the registerISRCallback is the C function, that accepts as first parameter the pin,
  //the interrupt is expected on and as second parameter a function pointer:
  //void (*callbackFunction)(int number, int time)
  registerISRCallback(SCLK, handle_interrupt);
}

void OurClass::handle_interrupt(int pin, int time) {
  //example: Blink a Led on the instance-LedPin
}

然而,问题有两个:

  1. 因为它是一个成员函数,handle_interrupt方法的签名是void (OurClass::*)(int, int),所以不能像这样使用。
  2. 该类可以实例化多次,因此使用单例也不起作用,因为我们的回调可能每个实例都不同(例如,每个实例可能具有不同的LedPin)。

有没有更多的解决方案可以在我们的类中使用这个C API函数,并保持代码整洁和易读?


3
不仅仅是因为C语言,同样在C++中调用成员函数需要实例化对象。如果有人期望一个自由函数作为回调函数,你不能交给他们一个成员函数。 - 463035818_is_not_a_number
3
保持从标记到实例的全局映射。你不能强制一个库与不兼容的模型一起工作。请记住,为了与 C 语言保持超级干净和标准兼容,回调函数也必须是一个 extern "C" 函数,因此成员变量(静态或非静态)是行不通的。 - StoryTeller - Unslander Monica
1
如果注册回调函数的函数不提供额外的参数,则无法完成此操作。使用额外的参数,例如 void*,您可以传递一个指向类的指针,并使用静态成员函数进行回调。 - Richard Critten
1
这个回答解决了您的问题吗?使用C++类成员函数作为C回调函数 - VLL
1
如果您有多个实例在其构造函数中注册中断,那么当中断发生时,您希望发生什么?悲观地说,我只期望最后一个注册的实例被调用。您是否尝试过(在C中,没有实例)向中断注册多个回调?这是可能的(如果调用代码实现了列表),但对于任何值得中断的内容来说,成本可能很高。 - Yunnosch
显示剩余3条评论
2个回答

3

你的类可以集成一个静态方法,作为你传递给C回调函数的方法(如果调用约定兼容,如果不可能,则将其包装在纯C调用中)。

此外,让你的类保持一个静态表格,对应于已创建实例的引脚。当回调被调用时,通过知道引脚,您将知道要激活哪个实例。


1
创建一个C风格的API(外部为C,内部为C ++),该API本身注册为单个回调并允许注册多个C ++回调。这将需要一些列表处理。
当中断发生时,调用它们所有并让它们根据回调参数决定是否需要做出反应。
或者,可以查看Story Teller的评论中更豪华的提案(将引脚映射到多个回调之一),该提案基本上在中央执行所需的回调检测。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接