如何将函数作为参数从 C 传递到 C++ 并传回 C

How to pass function as a parameter from C to C++ and back to C

本文关键字:C++ 函数 参数      更新时间:2023-10-16

设置:我正在构建一个架构,该架构的部分是C,部分是C++。

在我的架构中,我有:

  1. 获取数据的 data_io(C( 将其发送到处理器回调并输出处理后的数据。
  2. data_processor(C( 负责处理数据并按需更改。
  3. 决定使用哪个处理器的settings_manager(C++(。

关系如下:

  1. settings_manager对象被实例化,在它内部使用默认处理器函数初始化data_processor,然后初始化data_io向其发送processing_callback_function(在settings_manager中定义,但在内部引用data_processor函数(,然后在data_io启动时用于处理数据。(所以,data_io在初始化时只接收一次processing_callback_function,并不关心回调在里面做什么,它只是生成数据,调用processing_callback_function并输出处理后的数据(
  2. 当系统工作时,settings_manager可能会决定更改处理的data_processor类型,因此它会更改调用不同data_processor函数的processing_callback_function。(data_io不知道并继续工作(

以下是基本实现:

data_io.c:

typedef void (* ProcessorCallback_t)(float *, int);
ProcessorCallback_t processorCallback;
data_io_init(ProcessorCallback_t callback) {
processorCallback;
...init all other stuff like data pointer...
}
data_io_loop() {
bufSize = readData(&data); 
processorCallback(&data, bufSize);
writeData(&data, bufSize);
}

data_procesor.c:

void data_processor_init() {
...initialization routine...
}
void data_processor_proc1(float *data, int bufSize) {
...data process...
}
void data_processor_proc2(float *data, int bufSize) {
...data process...
}

settings_manager.cpp:

void SettingsManager::start() {
data_processor_init();
this->processing_function = &data_processor_proc1;
//THIS IS MY QUESTION! HOW TO PASS THE processing_callback_function TO data_io_init
data_io_init(&SettingsManager::processing_callback_function); 
... here starts a new thread to run loop below... 
//while(this->condition) { 
//    data_io_loop();
//}
}
void SettingsManager::changeProcessorType(int processorType) {
switch(processorType) {
case 1:
this->processing_function = &data_processor_proc1;
break;
case 2:
this->processing_function = &data_processor_proc2;
break;
}
}
void SettingsManager::processing_callback_function(float *data, int buffer_size) {
this->processing_function(data, buffer_size);
}

我的问题:

1. 如何将processing_callback_function C++成员函数传递给 data_io_init C 函数?

  • 当我执行以下操作时:

    data_io_init(&SettingsManager::p rocessing_callback_function(;

我收到以下错误:

"Incompatible pointer types 'ProcessorCallback_t' and 'void(Engine::*)(float*,int)'"

好吧,错误是显而易见的,类型是不同的,因为第二个是成员函数,并且是对象实例的一部分。

我读过我应该将processing_callback_function设为静态,但我不确定这是否是正确的方法。

  1. 处理这类事情的适当方法是什么,是否有任何读者可能对阅读有用,或者编码策略可能相关?

非静态类方法具有独立函数没有的隐藏this指针。 因此,您不能传递需要独立函数的非静态类方法。

在这种情况下,最好的解决方案是允许C++代码将用户定义的值传递给 C 代码,然后让 C 代码将该值传递回C++代码。 这样,C++代码就可以传递其this指针。 例如:

data_io.h:

typedef void (* ProcessorCallback_t)(float *, int, void *);
void data_io_init(ProcessorCallback_t callback, void *userdata);
void data_io_loop();

data_io.c:

ProcessorCallback_t processorCallback;
void *processorUserData;
void data_io_init(ProcessorCallback_t callback, void *userdata) {
processorCallback = callback;
processorUserData = userdata;
...init other stuff as needed ...
}
void data_io_loop() {
...
processorCallback(&data, bufSize, processorUserData);
...
}

然后SettingsManager可以这样做:

settings_manager.h:

typedef void (* ProcessorFunc_t)(float *, int);
class SettingsManager
{
private:
ProcessorFunc_t processing_function;
...
static void processing_callback_function(float *data, int buffer_size void *userdata);
public:
void start();
...
};

settings_manager.cpp:

#include "data_io.h"
void SettingsManager::start()
{
...
data_io_init(&SettingsManager::processing_callback_function, this); 
...
}
void SettingsManager::processing_callback_function(float *data, int buffer_size void *userdata)
{
static_cast<SettingsManager*>(userdata)->processing_function(data, buffer_size);
}

或者这个(因为上面是技术上未定义的行为,但它确实适用于大多数编译器。以下是更符合标准(:

settings_manager.h:

typedef void (* ProcessorFunc_t)(float *, int);
class SettingsManager
{
...
public:
ProcessorFunc_t processing_function;
void start();
...
};

settings_manager.cpp:

#include "data_io.h"
void processing_callback_function(float *data, int buffer_size void *userdata)
{
static_cast<SettingsManager*>(userdata)->processing_function(data, buffer_size);
}
void SettingsManager::start()
{
...
data_io_init(&processing_callback_function, this); 
...
}

1(用C++写下所有内容。使用 std::function 作为回调。这是处理此问题的最佳方法。您真的有性能问题吗?你测量过吗?C++并没有那么慢。混合两种语言样式会遇到的问题会带来更多问题。

2(C和C++中的函数相同。您始终可以执行以下操作:

class Cls {
public:
void callback() {}
};
void Cls_callback(void* ptr) {
reinterpret_cast<Cls*>(ptr)->callback();
}

然后将该Cls_callback作为 C 回调传递。

3(您可以Cls_callback成为静态Cls方法,这样它就可以访问Cls的私人成员:

class Cls {
public:
static void Cls_callback(void* ptr) {
Cls* self = reinterpret_cast<Cls*>(ptr);
self->i += 1;
}
private:
int i;
};

但请记住,这实际上是一个 UB。它将起作用,它的代码比变体 2 略少,但从技术上讲,标准并不能保证这将起作用。

附言再说一次,不要混合样式。随处使用C++。