打印
[技术讨论]

【C语言实战经验8】函数指针的常见应用

[复制链接]
81|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dffzh|  楼主 | 2025-6-26 17:09 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 dffzh 于 2025-6-26 17:11 编辑

#申请原创#
@21小跑堂


顾名思义,所谓的函数指针,也就是指向函数的指针变量,它是C/C++中一个特别有用的特性,允许程序代码将函数作为数据进行处理,其格式差不多就是下面这个造型:
返回值数据类型 (*函数指针变量名称)(形参1, …, 形参n );
那究竟函数指针有哪些应用呢?
如前所述,C/C++在编译时,每一个函数都有一个入口地址,该入口地址其实就是函数指针所指向的地址;有了指向函数的指针变量后,就可以用该指针变量调用函数,就如同用指针变量可以引用其他类型变量一样,而函数指针的常见应用主要包括以下几个方面。
1、回调函数机制
毫无疑问,函数指针最常见也是最经典的应用就是实现回调函数机制(callback),允许在特定事件发生时调用指定的函数。
所谓的回调函数,其实就是一个被作为参数传递的函数,而在C语言中,回调函数只能使用函数指针来实现。回调函数之所以应用非常多,是因为使用回调函数可以大大提升编程效率,有些通用性的代码需求还真的非它莫属。
下面列举一个通过函数指针实现回调函数的代码例子:
// 定义回调函数类型
typedef void (*callback)(int);

// 注册回调函数
void register_callback(callback cb)
{
    // 某些事件发生时
    int event_status = 111;
    cb(event_status);  // 调用回调函数
}

// 实际回调函数
void my_callback(int status)
{
    printf("Callback received status: %d\n", status);
}

int main()
{
    register_callback(my_callback);
    return 0;
}
仿真运行测试:
2、状态机驱动表(跳转表)
函数指针还有一个常见的应用就是用来实现状态机或者命令码的驱动表,现在很多人善于用表驱动法来实现MCU状态机管理,可以看下我之前发的一篇有关状态机设计的文章(链接https://bbs.21ic.com/icview-3457184-1-1.html),主要结构类似于下面这样:
typedef struct
{
    uint16_t uiCmd; //状态机或命令码
    void (*pHandler)(形参); //函数指针
} CommServerHandler_t;
//状态机驱动表
const CommServerHandler_t g_strCommServerHandler[] =
{
        { COMM_SERVER_IDLE, fCommServerVendorInfo},
        {COMM_SERVER_START, fCommServerVendorInfo},
        {COMM_SERVER_END, fCommServerVendorInfo},
    ……
};
//实际应用,对号入座即可
g_strCommServerHandler[i].pHandler(实参);
表驱动方法是一种让你可以在表中查找信息,而不必使用很多的逻辑语句来把它们找出来的方法,随着逻辑链的复杂,表驱动法会越来越有吸引力。
或者也可以试试使用函数指针数组来封装多个函数,请看下面代码:
void start() { printf("Starting...\n"); }
void stop() { printf("Stopping...\n"); }
void pause() { printf("Pausing...\n"); }

// 函数指针数组
void (*commands_callback[])() = {start, stop, pause};

void execute_command(int cmd)
{
    if (cmd >= 0 && cmd < sizeof(commands_callback)/sizeof(commands_callback[0]))
        {
        commands_callback[cmd]();
    }
}

int main()
{
    execute_command(0);
        execute_command(1);
        execute_command(2);
}
仿真运行测试:
这种设计,无论你的功能模块里有多少个应用函数,都可以封装到函数指针数组里,在调用时只要调用同一个函数即可实现,只是传参不同而已。
我们常用的计算器,如果用表驱动法方式来实现各种运算功能,肯定是比较经典的,即类似下面的框架:
typedef struct
{
    uint16_t uiCmd; //算术命令码
    void (*pCal_callback)(形参1,形参2); //函数指针
} calculator_t;

calculator_t  g_ calculator_handler[]
{
//加法命令码,加法函数
ADD, add_func,
//减法命令码,减法函数
SUB, sub_func,
//乘法命令码,乘法函数
MUL, mul_func,
//除法命令码,除法函数
DIV, div_func,
……
}
本文章主要就介绍函数指针的两种比较常见的应用,至于其他应用,包括作为函数参数传递和面向对象编程的模拟,其实大同小异,只要能通过这两种应用理解函数指针的本质就可以了。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

857

帖子

16

粉丝