C++向C传递回调函数-创新互联

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

创新互联公司专注为客户提供全方位的互联网综合服务,包含不限于成都网站建设、成都做网站、钟山网络推广、小程序设计、钟山网络营销、钟山企业策划、钟山品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们大的嘉奖;创新互联公司为所有大学生创业者提供钟山建站搭建服务,24小时服务热线:13518219792,官方网址:www.cdcxhl.com

文章目录
  • C++ 向 C 传递 回调函数
    • 前提
    • 静态函数
    • 定义新函数
    • lambda方法
    • 其他

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
#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#include#includeusing 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#include#includeusing 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#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#include#includeusing 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;

A::A(void) {
    auto adpter_for_lambda = [](int n, void *context) {
        FunctionCallback* pFunc = reinterpret_cast(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回调?

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网站栏目:C++向C传递回调函数-创新互联
URL网址:http://myzitong.com/article/deiegj.html