十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
文章目录背景:近期接手的项目中,需要将原来 C++ 中的一个底层接口替换为作者所写的 C,其中希望有一处地方希望 C++ 给 C 传递一个回调函数,以触发条件的时候调用该函数
创新互联公司专注为客户提供全方位的互联网综合服务,包含不限于成都网站建设、成都做网站、钟山网络推广、小程序设计、钟山网络营销、钟山企业策划、钟山品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们大的嘉奖;创新互联公司为所有大学生创业者提供钟山建站搭建服务,24小时服务热线:13518219792,官方网址:www.cdcxhl.com
(本人 C++ 小白一枚,仅以此篇记录遇到的问题并分享给各位,如有问题欢迎评论指正)
实验环境:
根据背景中提到的问题,我将该部分简化为一个 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元起,快前往官网查看详情吧