打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C|函数指针与回调函数模拟实现委托与反射

函数是C语言的核心概念。主调函数(caller)调用被调函数(callee)是一般的调用关系,如果被调函数(callee)参数包含函数指针,函数指针还可以形成多一层的调用关系,形成第三方函数的调用,专业术语称为回调(callback),通过函数指针参数调用的第三方函数称为回调函数。回调可以让被调函数(这里是指用函数指针做函数参数的函数)的代码更加泛化或抽象,能够简单模拟其它编程语言的委托与反射语法。

1 简单模拟委托

//C语言简单模拟委托//需要用的指针函数。通过用指针函数作为地址接收函数地址,以达到委托其他函数实现某方法的目的。#include <stdio.h>typedef void(* fun)(); //typedef 把void(*)()类型重命名为funvoid func(fun); // 被调函数void func_1(); // 回调函数1void func_2(); // 回调函数2int 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\n'); if (f != NULL) { f(); }}void func_1(){ printf('func_1\n');}void func_2(){ printf('func_2\n');}/*funcfunc_1func_2funcfunc_1funcfunc_2*/

2 简单模拟反射

//C语言简单模拟反射//高级语言的反射机制,简单来说就是可以通过字符串型获取对应的类或者函数。#if 0#include <stdio.h>#include <string.h>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;}#else/*上例的不便之处在于,当需要映射的函数因分散在不同文件时,每增加一个新的映射都需要修改这个数组,以及头文件。2 利用自定义段gcc支持通过使用__attribute__((section())),将函数、变量放到指定的数据段中。也就是说,可以让编译器帮我们完成上例中向数组添加成员的动作。借助此机制,回调函数可以在任意文件声明,不需要修改其他文件。自定义段的起始和结束地址,可以通过变量__start_SECTIONNAME和__stop_SECTIONNAME得到例如通过__attribute__((section('ss'))定义自定义段,其开始地址为&__start_ss,结束地址为&__stop_ss*/// https://www.bejson.com/runcode/c920/#include <stdio.h>#define SEC __attribute__((__section__('ss'), aligned(sizeof(void*))))void func_1 (int a, int b){    printf('%s %d %d\n', __func__, __LINE__, a+b); }void func_2 (int a, int b){    printf('%s %d %d\n', __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位于自定义段ssSEC 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 7func_2 10 24*/#endif

-End-

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
关于回调函数和this指针探讨
回调函数使用方法
C语言二维数组作为函数参数?(陷阱)
02选择题: 多态
基于Thunk技术的Windows Timer的封装
回调函数的注册机制为什么会在嵌入式固件开发中应用如此广泛?
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服