函数指针与软件设计

结构体内嵌函数指针实现分层 (1)程序为什么要分层? 因为复杂程序东西太多一个人搞不定,需要更多人协同工作,于是乎就要分工。要分工先分层,分层之后各个层次由不同的人完成,然后再彼此调用组合共同工作。 (2)本程序要完成一个计算器 我们设计了2个层次:上层是framework.c,实现应用程序框架;下层是cal.c,实现计算器。实际工作时cal.c是直接完成工作的,但是cal.c中的关键部分是调用的framework.c 阅读详情
来源: http://dev.youkuaiyun.com/author/absurd/6b43759193e74da4a4d911c0593af9f2.html

记得刚开始工作时,一位高手告诉我,说,longjmp和setjmp玩得不熟,就不要自称为C语言高手。当时我半信半疑,为了让自己向高手方向迈进,还是花了一点时间去学习longjmp和setjmp的用法。后来明白那不单是跳来跳去那样简单,而是一种高级的异常处理机制,在某些情况下确实很有用。

 

为 了显示自己的技巧,也在自己的程序中用过几次。渐渐发现这样的技巧带来的好处是有代价的,破坏了程序的结构化设计,程序变得很难读,尤其对新手来说。终于 明白这种技巧不过是一种调味料,在少数情况使用几次,可以简化对问题的处理。如果把调味拿来当饭吃,一定会本末倒置,写出的程序会呈现营养不良之状。

 

事实上,longjmp和setjmp玩得熟不熟与是不是C语言高手,不是因果关系。但是,如果可以套用那位高手的话,我倒想说如果函数指针玩得不熟,就不要自称为C语言高手。为什么这么说呢,函数指针有那么复杂吗?当然不是,任何一个稍有编程常识的人,不管他懂不懂C语言,在10分钟内,我想他一定可以明白C语言中的函数指针是怎么回事。

 

原 因在于,难的不是函数指针的概念和语法本身,而是在什么时候,什么地方该使用它。函数指针不仅是语法上的问题,更重要的是它是一个设计范畴。真正的高手当 然不单应该懂得语法层面上的技巧,更应该懂得设计上的方法。不懂设计,能算高手吗?怀疑我在夸大其辞吗?那我们先看看函数指针与哪些设计方法有关:

 

与分层设计有关。分层设计早就不是什么新的概念,分层的好处是众所周知的,比较明显好处就是简化复杂度、隔离变化。采用分层设计,每层都只需关心自己的东西,这减小了系统的复杂度,层与层之间的交互仅限于一个很窄的接口,只要接口不变,某一层的变化不会影响其它层,这隔离了变化。

 

分 层的一般原则是,上层可以直接调用下层的函数,下层则不能直接调用上层的函数。这句话说来简单,在现实中,下层常常要反过来调用上层的函数。比如你在拷贝 文件时,在界面层调用一个拷贝文件函数。界面层是上层,拷贝文件函数是下层,上层调用下层,理所当然。但是如果你想在拷贝文件时还要更新进度条,问题就来 了。一方面,只有拷贝文件函数才知道拷贝的进度,但它不能去更新界面的进度条。另外一方面,界面知道如何去更新进度条,但它又不知道拷贝的进度。怎么办? 常见的做法,就是界面设置一个回调函数给拷贝文件函数,拷贝文件函数在适当的时候调用这个回调函数来通知界面更新状态。

 

与抽象有关。抽象是面向对象中最重要的概念之一,也是面向对象威力强大之处。面向对象只是一种思想,大家都知道,用C语言一样可以实现面向对象的编程。这可不是为了赶时髦,而是一种实用的方法。如果你对此表示怀疑,可以去看看GTK+、linux kernel等开源代码。

 

接口是最高级的抽象。在linux kernel里面,接口的概念无处不在,像虚拟文件系统(VFS),它定义一个文件系统的接口,只要按照这种接口的规范,你可以自己开发一个文件系统挂上去。设备驱动程序更是如此,不同的设备驱动程序有自己一套不同的接口规范。在自己开发设备开发驱动程序时,只要遵循相应的接口规范就行了。接口在C语言中如何表示?很简单,就是一组函数指针。

 

与接口与实现分开有关。针对接口编程,而不是针对实现编程,此为《设计模式》的第一条设计准则。分开接口与实现的目标是要隔离变化。软件是变化的,如果不能把变化的东西隔离开来,导致牵一发而动全身,代价是巨大的。这是大家所不愿看到的。

 

C语言既然可以实现面向对象的编程,自然可以利用设计模式来分离接口与实现。像桥接模式、策略模式、状态模式、代理模式等等,在C语言中,无一不需要利用函数指针来实现。

 

与松耦合原则有关。 面向过程与面向对象相比,之所以显得苍白无力,原因之一就是它不像面向对象一样,可以直观的把现实模型映射到计算机中。面向过程讲的是层层控制,而面向对 象更强调的对象间的分工合作。现实世界中的对象处于层次关系的较少,处于对等关系的居多。也就是说,对象间的交互往往是双向的。这会加强对象间的耦合性。

 

耦合本身没有错,实际上耦合是必不可少的,没有耦合就没有协作,对象之间无法形成一个整体,什么事也做不了。关键在于耦合要恰当,在实现预定功能的前提下,耦合要尽可能的松散。这样,系统的一部分变化对其它部分的影响会很少。

 

函数指针是解耦对象关系的最佳利器。Signal(如boost的signal和glib中的signal)机制是一个典型的例子,一个对象自身的状态可能是在变化的(或者会触发一些事件),而其它对象关心它的变化。一旦该对象有变化发生,其它对象要执行相应的操作。

 

如果该对象直接去调用其它对象的函数,功能是完成了,但对象之间的耦合太紧了。如何把这种耦合降到最低呢,signal机制是很好的办法。它的原理大致如下:其它关注该对象变化的对象主动注册一个回调函数到该对象中。一旦该对象有变化发生,就调用这些回调函数通知其它对象。功能同样实现了,但它们之间的耦合度降低了。

 

在C语言中,要解决以上这些问题,不采用函数指针,将是非常困难的。在编程中,如果你从没有想到用函数指针,很难想像你是一个C语言高手。

C++之指针探究(十七):结构体内嵌函数指针实现分层 主题:结构体内嵌函数指实现分层   (1)程序为什么要分层?因为复杂程序东西太多一个人搞不定,需要更多人协同工作,于是乎就要分工。要分工先分层,分层之后各个层次由不同的人完成,然后再彼此调用组合共同工作。   (2)本程序要完成一个计算器。实际工作时cal.c是直接完成工作的,但是cal.c中的关键部分是调用的framework.c中的函数来完成的。   (3)先写framework.c由一个人来完成。这个人在framework.c中需要完成计算器的业务逻辑,并且把相应的接口写在对应的头文件中发出来,将来. 阅读详情

相关推荐

保姆级教程:用Intouch SMC连接S7-200 Smart PLC,Modbus TCP和S7协议一次搞定

本文详细介绍了如何使用Intouch SMC连接S7-200 Smart PLC,涵盖Modbus TCP和S7协议的双协议通信配置。通过环境准备、参数设置、常见问题排查及实战技巧,帮助工程师快速实现工业自动化系统中的稳定通信,提升设备监控效率。

weixin_30499315的博客 433

函数指针的妙用,可以快速实现底层与应用层的分开编写

#include <iostream> using namespace std; void fun1(void) { cout<<"fun1 is called"<<endl; } void fun2(void) { cout<<"fun2 is called"<<endl; } typedef struct{ void (*P1) (void); void (*p2) (void); }call; int mai.

weixin_42145502的博客 286

从FinFET到GAA:手把手解读2nm芯片制造的关键技术(含BSPDN避坑指南)

本文深入解读了2nm芯片制造从FinFET向全环绕栅极(GAA)晶体管架构演进的核心技术,并重点剖析了背面供电网络(BSPDN)的三种实现路径及其工程挑战。文章旨在帮助工程师理解技术变革的内在逻辑,并为应对2nm节点设计中的关键问题提供实用指南。

weixin_29294975的博客 292

初论c程序的分层架构案例

懒得码字,直接借用朱有鹏老师课件内容 主题:结构体内嵌函数指针实现分层 (1)程序为什么要分层?因为复杂程序东西太多一个人搞不定,需要更多人协同工作,于是乎就要分工。 要分工先分层,分层之后各个层次由不同的人完成,然后再彼此调用组合共同工作。 (2)本程序要完成一个计算器,我们设计了2个层次: 上层是framework.c,实现应用程序框架;下层是cal.c,实现计算器。 实际工作时c...

zw1996的博客 1408

机器学习实例(预测房价中位数)(附代码)

1、下载数据: 下载一个压缩文件housing.tgz即可,其包含housing.csv(已经包含书有数据。),用 tax xzf housing.tgz 来解压提取CSV文件。 import os import tarfile import urllib.request DOWNLOAD_ROOT = "https://raw.githubusercontent.com/ageron/handson-ml2/master/" HOUSING_PATH = os.path.join("datasets",

qq_51153436的博客 2758

Unity物理驱动3D汽车实现:从刚体控制到参数调优

在游戏开发中,刚体物理是实现真实物体运动与交互的核心技术。通过Unity的物理引擎,开发者可以模拟重力、碰撞、摩擦力等物理行为,为游戏世界注入真实感。其技术价值在于能够以符合物理规律的方式驱动游戏对象,避免穿墙、无视惯性等问题,从而提升游戏体验的真实性和沉浸感。这一原理广泛应用于角色控制、车辆模拟、物体破坏等场景。本文以3D小汽车为例,详细解析了如何通过Rigidbody组件施加力与扭矩,并利用C#脚本实现玩家输入逻辑,完成一辆可操控、能碰撞的物理驱动汽车。文中重点探讨了AddForce与角速度控制两种方案

weixin_34380948的博客 501

C函数指针与软件设计

c函数指针与软件设计

zhen 200

STM32 Modbus-RTU从零到实战:手把手教你用HAL库实现工业通信(附完整代码)

本文详细介绍了如何使用STM32 HAL库从零开始实现Modbus-RTU从机通信。内容涵盖RS485硬件设计、CubeMX串口与定时器配置、基于空闲中断的高效数据接收、协议栈状态机设计、CRC16校验实现以及常用功能码处理。文章提供了完整的代码框架和调试方法,帮助开发者快速构建稳定的工业通信节点。

weixin_28278377的博客 188

函数指针与软件设计_函数指针 解耦

接口是最高级的抽象。在linux kernel里面,接口的概念无处不在,像虚拟文件系统(VFS),它定义一个文件系统的接口,只要按照这种接口的规范,你可以自己开发一个文件系统挂上去。采用分层设计,每层都只需关心自己的东西,这减小了系统的复杂度,层与层之间的交互仅限于一个很窄的接口,只要接口不变,某一层的变化不会影响其它层,这隔离了变化。Signal(如boost的signal和glib中的signal)机制是一个典型的例子,一个对象自身的状态可能是在变化的(或者会触发一些事件),而其它对象关心它的变化。

2401_87555681的博客 402

Ubuntu 20.04 上 Geant4 安装避坑全记录:从源码编译到 B1 示例跑通(含数据包加速下载)

本文详细记录了在Ubuntu 20.04系统上从源码编译安装Geant4的全过程,包括环境准备、依赖安装、CMake参数解析、多线程编译优化以及数据包加速下载等关键步骤。特别针对B1示例的测试与验证提供了完整流程,帮助科研人员和学生避开常见安装陷阱,提升粒子物理模拟效率。

weixin_31220401的博客 312

Buck电源设计常见的一些问题(一)半桥栅极驱动芯片共性失效问题

半桥驱动芯片主要用在器件可应用于电信,数据通信,便携式存储或更低电压系统中的电源转换器,半桥、全桥、推挽、同步降压,正激变换器和同步整流器等方面。当然难免会遇到不少问题。基本上我们在产品开发的过程中都遇到过栅极驱动芯片坏掉的情况,所以找了一些资料,学习学习。也查找查找原因。

小幽余生不加糖 2369
上一篇: 再议回调函数
下一篇: 怎样挑二手本本
lphpc
博客等级 码龄22年 32粉丝 86原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值