C++向C传递回调函数

背景:近期接手的项目中,需要将原来 C++ 中的一个底层接口替换为作者所写的 C,其中希望有一处地方希望 C++ 给 C 传递一个回调函数,以触发条件的时候调用该函数
(本人 C++ 小白一枚,仅以此篇记录遇到的问题并分享给各位,如有问题欢迎评论指正)

C++ 向 C 传递 回调函数

前提

实验环境:

  • ubuntu20.04
  • gcc version 9.4.0

根据背景中提到的问题,我将该部分简化为一个 demo, 主要包含 c_test.h c_test.c c++_test.cpp 三个文件
除此之外还有一个 Makefile,因为几个方法的 Makefile 都相同,故在此展示

CC = gcc                                                                                                         
CXX = g++ 
TARGET = test

AllDIRS := $(shell ls -R | grep '^\./.*:$$' | awk '{gsub(":","");print}') .
CSRCS = $(foreach n,$(AllDIRS) , $(wildcard $(n)/*.c)) 
CXXSRCS = $(foreach n,$(AllDIRS) , $(wildcard $(n)/*.cpp)) 
OBJS := $(CSRCS:.c=.o) $(CXXSRCS:.cpp=.o)

SRC_PATH = ./
INC_PATH = -I $(SRC_PATH) 

#compile
%.o : %.c 
    $(CC) $(INC_PATH) -c $< -o $@ -g
%.o : %.cpp
    $(CXX) $(INC_PATH) $< -c -o $@ -g

#links
$(TARGET) : $(OBJS)
    $(CXX) $^ -g -o $@ $(INC_PATH)
    @rm -rf $(OBJS)
    @echo "build success"

.PHONY:clean
clean:
    @echo "Remove linked and compiled files......"
    rm -rf $(OBJS) $(TARGET)

静态函数

使用静态函数,该方法是最为简单的,跟 C 中没有太多区别,直接上代码
c_test.h

#ifndef C_TEST_H_                                    
#define C_TEST_H_

#ifdef __cplusplus
extern "C" 
{
#endif

typedef void (*Callback)(int);
typedef struct c_test {
    Callback callback;
}c_test_t;

void c_run(Callback fun);

#ifdef __cplusplus
}
#endif
#endif

c_test.c

#include <stdio.h>                                
#include "c_test.h"

void c_run(Callback fun){
    c_test_t c_test;
    c_test.callback = fun;
    c_test.callback(2);
}

c++_test.c

#include "c_test.h"                            
#include <stdio.h>
#include <iostream>
#include <functional>
using namespace std;

namespace test_interface {
class A {
public:
    A(void);
private:
    static int a_private_var;
static void fn(int i) {
    test_interface::A::a_private_var = 1;
    printf("%d\n", test_interface::A::a_private_var);
    printf("%d\n", i); 
} 

};
}

int test_interface::A::a_private_var;

namespace test_interface {
A::A(void) {
    c_run(A::fn);
}
}

int main(int argc, char* argv[]) {
    test_interface::A a;
    return 0;
}

通过代码可以看见,该方法的缺陷在于 C++传递的 callback 函数必须是静态函数,这样内部使用的变量也就只能是静态变量了,属于整个类了,而不属于某个对象,这是很糟糕的,但不得不说该方法确实 easy

定义新函数

在 C++ 中定义一个 Callback类型的函数,在该函数中声明类对象,将该函数传递给 C
该方法中仅 c++_test.c 文件不一样
c++_test.c

#include "c_test.h"      
#include <stdio.h>
#include <iostream>
#include <functional>
using namespace std;

namespace test_interface {
class A { 
public:
    void fn2(int i) { fn(i); }
private:
    int a_private_var;
    void fn(int i) {
        test_interface::A::a_private_var = 1;
        printf("%d\n", test_interface::A::a_private_var);
        printf("%d\n", i); 
    }   
};
}

void new_func(int n) {
    test_interface::A a;
    a.fn2(n);
}

int main(int argc, char* argv[]) {
    c_run(&new_func);
    return 0;
}

lambda方法

来到重头戏了,前两种方法在我项目中都不适用,所以找到了这篇博客
其对通过 lambda 向 C 传递给函数指针回调作了多种实验以及测试,代码详情可参考代码地址
对于 lambda 不是很了解的可以参考
lambda概念与用法
lambda概念与用法

本篇主要参考了示例5 ,使用*void 上下文指针将捕获 lambda 传递给 C 函数指针回调
c_test.h

#ifndef C_TEST_H_
#define C_TEST_H_

#ifdef __cplusplus
extern "C" 
{
#endif

typedef void (*Callback)(int, void* context);
typedef struct c_test {
    Callback callback;
    void *callback_context;
}c_test_t;

void c_run(Callback fun, void* context);

#ifdef __cplusplus
}
#endif

#endif

c_test.c

#include <stdio.h>
#include "c_test.h"

void c_run(Callback fun, void* context){
    c_test_t c_test;
    c_test.callback = fun;
    c_test.callback_context = context;

    c_test.callback(2, c_test.callback_context);
}

c++_test.c

#include "c_test.h"
#include <stdio.h>
#include <iostream>
#include <functional>
using namespace std;

namespace test_interface {
class A {
public:
    A(void);
private:
    int a_private_var;
    void fn(int i) {
        A::a_private_var = 1;
        printf("%d\n", A::a_private_var);
        printf("%d\n", i);
    }
};
}

namespace test_interface {

using FunctionCallback = std::function<void (int data)>;

A::A(void) {
    auto adpter_for_lambda = [](int n, void *context) {
        FunctionCallback* pFunc = reinterpret_cast<FunctionCallback*>(context);
        (*pFunc)(n);
    };
    auto callback_lambda = [this](int n) { A::fn(n); };

    FunctionCallback callback_object = callback_lambda;

    c_run(adpter_for_lambda, &callback_object);
}

}

int main(int argc, char* argv[]) {
    test_interface::A a;
    return 0;
}

该例是通过 C 提供一个额外的空指针,用来指向函数指针的上下文或状态

其他

另外一篇参考博客如何将C++λ传递给需要函数指针和上下文的C回调?

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值