C语言使用回调函数模拟委托与反射

函数是C语言的核心概念。主调函数(caller)调用被调函数(callee)是一般的调用关系,如果被调函数(callee)参数包含函数指针,函数指针还可以形成多一层的调用关系,形成第三方函数的调用,专业术语称为回调(callback),通过函数指针参数调用的第三方函数称为回调函数。

回调可以让被调函数(这里是指用函数指针做函数参数的函数)的代码更加泛化或抽象,能够简单模拟其它编程语言的委托与反射语法。

1、简单模拟委托

//C语言简单模拟委托

//需要用的指针函数。通过用指针函数作为地址接收函数地址,以达到委托其他函数实现某方法的目的。

#include

typedef void(* fun)(); //typedef 把void(*)()类型重命名为fun

void func(fun); // 被调函数

void func_1(); // 回调函数1

void func_2(); // 回调函数2

int main() // 主函数用做主调函数

{

func(func_1);

fun f = func_2;

f();

func(func_1);

func(func_2);

getchar();

return 0;

}

void func(fun f) //fun f为地址,fun * f为f指向的地址的量或者其他

{

printf(“func

“);

if (f != NULL)

{

f();

}

}

void func_1()

{

printf(“func_1

“);

}

void func_2()

{

printf(“func_2

“);

}

/*

func

func_1

func_2

func

func_1

func

func_2

*/

2、简单模拟反射

(1)简单模拟反射

高级语言的反射机制,简单来说就是可以通过字符串型获取对应的类或者函数。

下面用C来简单模拟反射:

#include

#include

typedef void (*callback)(void);

typedef struct {

const char *name;

callback fn;

}callback_t;

void f0();

void f1();

callback_t callbacks[] = {

{“cmd0”, f0},

{“cmd1”, f1},

};

void f0() // 回调函数0

{

printf(“cmd0”);

}

void f1() // 回调函数1

{

printf(“cmd1”);

}

void do_callback(const char *name)

{

size_t i;

for (i = 0; i < sizeof(callbacks) / sizeof(callbacks[0]); i++) {

if (!strcmp(callbacks[i].name, name)) {

callbacks[i].fn();

}

}

}

int main()

{

do_callback(“cmd1”);

getchar();

return 0;

}

(2)利用自定义段

gcc支持通过使用 __ attribute __ ((section())),将函数、变量放到指定的数据段中。

也就是说,可以让编译器帮我们完成上例中向数组添加成员的动作。借助此机制,回调函数可以在任意文件声明,不需要修改其他文件。自定义段的起始和结束地址,可以通过变量 __ start_SECTIONNAME 和 __ stop_SECTIONNAME得到例如通过 __ attribute __ ((section(“ss”))定义自定义段,其开始地址为 & __ start_ss,结束地址为 & __stop_ss。

// https://www.bejson.com/runcode/c920/

#include

#define SEC __attribute__((__section__(“ss”), aligned(sizeof(void*))))

void func_1 (int a, int b)

{

printf(“%s %d %d

“, __func__, __LINE__, a+b);

}

void func_2 (int a, int b)

{

printf(“%s %d %d

“, __func__, __LINE__, a*b);

}

// 编译器会自动提供__start_ss,__stop_ss标志段ss的起止地址

extern size_t __start_ss;

extern size_t __stop_ss;

typedef struct {

void (*p)(int, int);

} node_t;

// 结构体变量a位于自定义段ss

SEC node_t a = {

.p = func_1,

};

SEC node_t b = {

.p = func_2,

};

int main(int argc, char **argv)

{

int a = 3, b = 4;

node_t *p;

// 遍历段ss,执行node_t结构中的p指向的函数

for (p = (node_t *)&__start_ss; p < (node_t *)&__stop_ss;p++) {

p->p(a, b);

a+=1;b+=2;

}

}

/*

func_1 6 7

func_2 10 24

*/

审核编辑:汤梓红

发表评论