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

Posted

技术标签:

【中文标题】如何将函数作为参数从 C 传递到 C++ 并返回到 C【英文标题】:How to pass function as a parameter from C to C++ and back to C 【发布时间】:2017-08-03 19:19:01 【问题描述】:

设置:我正在构建一个包含 C 部分和 C++ 部分的架构。

在我的架构中,我有:

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

关系如下:

    settings_manager 对象被实例化,在其内部使用默认处理器函数初始化 data_processor,然后初始化 data_io 向其发送 processing_callback_function(在 settings_manager 中定义,但在内部引用 data_processor 函数),然后用于处理data_io 启动时的数据。 (所以,data_io在初始化时只接收一次processing_callback_function,并不关心callback在里面做什么,它只是生成数据,调用processing_callback_function并输出处理后的数据) 在系统工作时,settings_manager 可能会决定更改处理的 data_processor 类型,因此它会更改 processing_callback_function 以调用不同的 data_processor 函数。(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::processing_callback_function);

我收到以下错误:

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

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

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

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

【问题讨论】:

C 中的部分(为了获得最佳性能,无需类转换或多次耗时的内存解析)您对 C++ 的假设是错误的。 你是怎么编译这些文件的,SettingsManager的定义是什么? @manni66 请解释一下我很想学习,可以回答我的第二个问题 “C++ 对于时间关键部分来说太慢了”——现在这是核心。 @alexm 由于 C 几乎是 C++ 的一个子集,因此 C 代码不能比精心编写的 C++ 更快(除非您使用不同的编译器)。在最坏的情况下,性能将是相同的。为了让您的生活更轻松,您可以将所有内容编译为 C++。 【参考方案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); 
    ...

【讨论】:

【参考方案2】:

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++。

【讨论】:

以上是关于如何将函数作为参数从 C 传递到 C++ 并返回到 C的主要内容,如果未能解决你的问题,请参考以下文章

如何将constexpr作为函数参数传递c ++ [重复]

从 C++ 调用 python 函数时如何将 C++ 类作为参数传递?

c++ - 如何将void函数作为参数传递?

使用 jni 将位图从 android 相机传递到 C++

如何将数组从 c++ 传递给 python 函数并将 python 返回的数组检索到 c++

如何将参数从c ++传递到linux shell