函数结构体应用实例
一、函数结构体使用的优点适用场景裸机 / RT‑Thread 嵌入式 C99 开发STM32 项目常用用结构体保存成员数据 函数指针保存操作接口实现 C 语言伪面向对象。1. 数据和行为聚合高内聚普通写法全局变量分散、功能函数独立 结构体把模块状态数据和操作该数据的函数接口打包在一起。相关变量、操作集中管理阅读代码一眼看懂模块有什么数据、能做什么动作。避免大量零散全局变量减少全局命名污染。2. 支持实例化一套代码多个对象最大优势之一结构体可以定义多个实例。 例如一个继电器驱动结构体可以实例化 relay1、relay2共用同一套函数实现只各自保存独立状态。如果用全局变量写驱动要复制多份全局代码大量重复维护灾难。ModuleObj_t dev1; ModuleObj_t dev2; dev1.init(); dev2.init();3. 接口隐藏、封装信息隐藏头文件只暴露结构体前向声明不展开内部成员内部数据私有化外部不能直接访问内部变量只能调用提供的函数指针接口读写外部只能调用对外提供接口禁止直接修改内部状态防止外部乱改成员造成状态异常内部实现改动只要接口函数指针原型不变上层业务代码完全不用修改。4. 多态便于适配不同硬件 / 型号非常适合 STM32 多芯片兼容F407/F030、不同外设硬件适配。相同函数接口原型底层绑定不同实现上层调用完全一致。 举例obj.init drv_f030_init; //F030版本底层实现 //obj.init drv_f407_init;//F407版本底层实现 obj.init();//上层调用代码无需改动可以做到上层业务逻辑一套底层硬件实现按需替换配合条件编译完成多型号适配。5. 降低耦合分层清晰上层业务只操作对象结构体接口不需要依赖底层具体函数名。底层驱动修改、BUG 修复只要接口签名不变业务层代码不用改动。便于模块解耦模块之间只传对象句柄结构体指针不互相引用大量全局。6. 便于单元测试、模拟 mock测试的时候可以把结构体里函数指针替换成模拟 mock 函数不需要真实硬件就可以测试上层业务逻辑。 比如把硬件读写函数指针替换成仿真函数PC 上即可做模块单元测试。二、对应的缺点工程需要权衡有少量内存开销每个实例会占用若干函数指针4 字节 / 个32 位 MCU实例很多时要关注 RAM 占用调试难度略上升函数指针跳转Keil 断点不能直接跳进实现需要看指针指向的真实函数对开发人员要求高错误赋值函数指针会直接跑 HardFault必须严格做参数校验C 语言本身没有访问控制语法“私有” 依靠编码约定强制前向声明才能真正禁止外部访问结构体内部。三、对比普通全局函数 全局变量 vs 结构体函数指针表格维度全局变量 普通函数结构体 函数指针多实例需要复制多份全局重复代码直接定义多个结构体实例封装性外部可随意修改全局变量可隐藏内部成员仅接口访问耦合度业务层硬编码调用底层函数名依赖抽象接口底层可替换多态适配大量 #ifdef 分散业务代码同一套上层底层替换函数指针内存占用全局永久占用 RAM实例按需分配多几个指针开销调试直接断点函数指针间接跳转调试稍麻烦四、应用实例led灯控制初始化、亮、灭、翻转、短暂闪烁、获取当前状态。#ifndef _DEV_LEDRUN_H #define _DEV_LEDRUN_H //----------------------------------------------- // 枚举定义 //----------------------------------------------- typedef enum { LED_RUN_OFF 0, // 灯灭 LED_RUN_ON 1, // 灯亮 } LedRun_StateEnum; //----------------------------------------------- // 接口结构体 //----------------------------------------------- typedef struct { void (*Init)(void); // 初始化 void (*SetOn)(void); // 亮 void (*SetOff)(void); // 灭 void (*Toggle)(void); // 翻转 void (*Blink_Short)(uint8_t times); // 短暂闪烁可设次数 LedRun_StateEnum (*GetState)(void); // 获取当前状态 } LedRun_OpTypeDef; typedef struct { LedRun_StateEnum currentState; const LedRun_OpTypeDef op; } LedRun_DeviceTypeDef; extern LedRun_DeviceTypeDef dev_LedRun; #endif//---------------------------------------------------------------------- //描述: 运行指示灯接口配置与使用源文件 //---------------------------------------------------------------------- #include Dev_LedRun.h //----------------------------------------------- // 运行灯引脚定义 //----------------------------------------------- #define LED_RUN_PORT GPIOC #define LED_RUN_PIN GPIO_Pin_15 #define LED_RUN_CLK RCC_AHBPeriph_GPIOC //----------------------------------------------- // 内部函数声明 //----------------------------------------------- static void LedRun_Init(void); static void LedRun_SetOn(void); static void LedRun_SetOff(void); static void LedRun_Toggle(void); static void LedRun_Blink_Short(uint8_t times); static LedRun_StateEnum LedRun_GetState(void); //----------------------------------------------- // 对外设备实例C99 //----------------------------------------------- LedRun_DeviceTypeDef dev_LedRun { .currentState LED_RUN_OFF, .op { .Init LedRun_Init, .SetOn LedRun_SetOn, .SetOff LedRun_SetOff, .Toggle LedRun_Toggle, .Blink_Short LedRun_Blink_Short, .GetState LedRun_GetState, } }; //----------------------------------------------- // 函数实现 //----------------------------------------------- //---------------------------------------------------------------------- //函数功能: 运行灯初始化 //参数: 无 //返回值: 无 //备注: PB10推挽输出默认灯灭 //---------------------------------------------------------------------- static void LedRun_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_AHBPeriphClockCmd(LED_RUN_CLK, ENABLE); GPIO_InitStruct.GPIO_Pin LED_RUN_PIN; GPIO_InitStruct.GPIO_Mode GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(LED_RUN_PORT, GPIO_InitStruct); LedRun_SetOff(); } //---------------------------------------------------------------------- //函数功能: 灯常亮低电平点亮 //---------------------------------------------------------------------- static void LedRun_SetOn(void) { GPIO_WriteBit(LED_RUN_PORT, LED_RUN_PIN, Bit_RESET); dev_LedRun.currentState LED_RUN_ON; } //---------------------------------------------------------------------- //函数功能: 灯常灭高电平熄灭 //---------------------------------------------------------------------- static void LedRun_SetOff(void) { GPIO_WriteBit(LED_RUN_PORT, LED_RUN_PIN, Bit_SET); dev_LedRun.currentState LED_RUN_OFF; } //---------------------------------------------------------------------- //函数功能: 电平翻转 //---------------------------------------------------------------------- static void LedRun_Toggle(void) { if(dev_LedRun.currentState LED_RUN_ON) LedRun_SetOff(); else LedRun_SetOn(); } //---------------------------------------------------------------------- //函数功能: 短暂闪烁可设置次数 //参数: times: 闪烁次数 //---------------------------------------------------------------------- static void LedRun_Blink_Short(uint8_t times) { uint8_t i; if(times 0) return; for(i 0; i times; i) { LedRun_SetOn(); delay_ms(60); LedRun_SetOff(); delay_ms(60); } } //---------------------------------------------------------------------- //函数功能: 获取当前灯状态 //---------------------------------------------------------------------- static LedRun_StateEnum LedRun_GetState(void) { return dev_LedRun.currentState; }

相关新闻

宝宝餐后常喊肚子疼?这背后的原因你可能没想到

宝宝餐后常喊肚子疼?这背后的原因你可能没想到

宝宝餐后常喊肚子疼?这背后的原因你可能没想到最近一两个月,宝宝经常在饭后出现腹部绞痛的情况,已经发生了三次左右。每次持续约三分钟,并伴有轻微腹泻。我在他痛的时候尝试揉肚角和肚脐,但他痛得不让我动他。后来听其…

2026/11/14 10:02:46 阅读更多 →
Vim代码补全实战:从Ctags到LSP,打造高效开发环境

Vim代码补全实战:从Ctags到LSP,打造高效开发环境

1. 项目概述:为什么要在Vim里折腾代码补全? 在Linux环境下,Vim编辑器以其高效、轻量和无处不在的特性,成为无数开发者、系统管理员和极客的首选。然而,对于习惯了现代IDE(如IntelliJ IDEA、PyCharm&#x…

2026/11/13 0:42:11 阅读更多 →
JPEXS 反编译工具从入门到精通的完整实战指南

JPEXS 反编译工具从入门到精通的完整实战指南

JPEXS 反编译工具从入门到精通的完整实战指南 【免费下载链接】jpexs-decompiler JPEXS Free Flash Decompiler 项目地址: https://gitcode.com/gh_mirrors/jp/jpexs-decompiler JPEXS Free Flash Decompiler(FFDec) 是一款开源免费的 Flash SWF …

2026/11/13 12:23:12 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/14 5:13:29 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/14 5:13:29 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/14 5:13:29 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/13 22:08:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/14 2:41:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/14 5:13:29 阅读更多 →

日新闻

周新闻

月新闻