当前位置: 首页 > news >正文

书摘:C 嵌入式系统设计模式 02

本书的原著为:《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》,讲解的是嵌入式系统设计模式,是一本不可多得的好书。

本系列描述我对书中内容的理解。

结构化编程将软件组织成两个截然不同的方面:数据和行为。面向对象的方法将两者结合起来,让紧密耦合的元素更内聚,并提高内容的封装。C 是结构化语言,但它可以用于开发面向对象的嵌入式系统。

这里提到了 结构化编程面向对象编程 ,C 语言支持结构化编程, C++ 则支持面向对象编程。其实到目前为止,还有第 3 种编程范式,那就是 函数式编程 。这三种编程范式至今都在广泛使用,它们诞生至今已经有相当长的时间了。正如我在《关于编程》中提到的:

  • 1958 年 John Mccarthy 发明了 LISP 语言,函数式编程 范式诞生
  • 1966 年 Ole Johan DahlKriste Nygaard 的论文开创了 面向对象编程 范式
  • 1968 年 Edsger Wybe Dijkstra 论证了 goto 语句的危害,结构化编程 范式诞生

经过了几十年的发展,今天的编程范式与过去完全一样,也是结构化编程 范式、 面向对象编程 范式和 函数式编程 范式,再没有出现新的编程范式。

结构化编程 的核心理念是将复杂的程序问题分解为更小、更容易管理的子问题。“结构化”在这里意味着用只用有限的几种结构(顺序、分支、循环)来构建程序,避免使用 goto 等可能导致程序流程难以跟踪和控制的结构。

结构化编程是由 Edsger Wybe Dijkstra 于 1968 年提出的。Dijkstra 于1930 年出生于荷兰,他很早就发现编程是一件难度很大的工作。一段程序无论复杂与否,都包含了很多细节信息,这远超一个程序员的认知能力范围。而即便是一个小细节的错误,也会造成整个程序出错。他想用数学来证明程序是正确的,而且他也成功了。

Dijkstra 在研究的过程中发现了一个问题:不加限制的 goto 语句导致模块无法拆分成更小的、可被证明的单元,如果禁用 goto,只使用顺序结构、分支结构(if-then-else)和循环结构(do–while)编程,那么程序就可以被数学所证明。于是,结构化编程诞生了。

1968 年,Dijkstra 写了那封著名的,后来发表于 CACM ,标题为《Go To Statement Considered Harmful》的文章。“goto 是有害的”这个观点,这在当时引起了很多程序员的不满。在当时,使用汇编跳转是家常便饭,因此 Dijkstra 的观点掀起了一场长达 10 年的辩论。然而,最后辩论还是平息了,因为事实证明, Dijkstra 是对的。

Dijkstra 的工作是证明一段程序在数学上是正确的,这在实际操作中可太难了。工程界采用的是方法是证明这个程序是错误的,证伪可比证实简单多了,只要能找到一个 BUG,证明就结束了。如果这段程序经过一定的努力无法证伪,我们则认为它在当下是足够正确的。值得注意的是,只有在可证明的程序上,才可以使用这种方法证伪。如果某段程序采用了不加限制的 goto 语句,那么再多的测试也不能证明其正确性。

结构化编程范式促使我们将功能递归的分解为一系列可证明的小函数,然后再编写相关的测试来试图证明这些函数是错的。如果这些测试无法证伪这些函数,那么我们就可以认为这些函数是足够正确的,进而推导整个程序是正确的。

作者说“结构化编程将软件组织成两个截然不同的方面:数据和行为。面向对象的方法将两者结合起来,让紧密耦合的元素更内聚,并提高内容的封装。”这句话我并不是很理解,在我的认识里,无论结构化编程还是面向对象编程,优秀的程序员们总是首先关注数据结构,不仅要考虑如何表示数据,还要考虑如何使用数据。因此无论用什么编程范式,数据和行为都是天然结合起来的,不存在结构化编程将软件组织成两个截然不同的方面。不同的是,结构化编程语言在 文件 中实现数据和行为的结合,面向对象编程在 中实现数据和行为的结合,从本质上讲,这不过是形式上的不同,思想上,它们是一致的。

然后是关于封装。封装就是隐藏不必要的细节,包括数据结构和实现细节。一个最好的例子是文件系统。文件系统的实现非常复杂,有一个很大的数据结构,但这些都被精心隐藏起来了,你只需要操作几个简单的函数 openreadwrite,就可以完成大部分文件操作。模块的头文件就是模块的接口,这里面可以只有 API 函数声明,没有任何数据结构的声明,但 C++ 就办不到,因为技术的限制,C++ 的头文件中必须包含类的声明,这样类中的所有元素都暴露在外了。如果只是谈封装,C 语言是要好于 C++ 的。

“C 可以用于开发面向对象的嵌入式系统”,这是书中的一个结论。我认同这个结论,不是说要使用复杂的宏定义封装 C 语言,模仿 C++ 的语法,而是要深刻理解面向对象的思想,站在更高的层次上编程,首先要理解的,也是最重要的,是 多态

多态 是指多种形态,就是指同一个方法的行为随上下文而异。归根结底,多态不过是函数指针的一种应用。举一个例子:某设备具有多种运行模式:普通模式、访客模式、特权模式…,对于每种模式,显示方式不同、控制逻辑不同、上传的数据也不同。遇到这样的情况,你会下意识用 switch - case 语句解决吗?如果你使用 switch - case 语句解决,那么在显示、控制、上传这些地方,都会有一个 switch - case 语句,不断地重复各种模式。这还没完,当你新增一个模式时,还需要在所有关于模式的 switch 语句处增加 case 语句,来处理新的模式。可以用函数指针代替 switch - case 语句。

首先,我们抽象出一个接口,接口就是一系列函数指针,这些指针规定了每种模式都需要操作的函数原型。然后每种模式都自己实现这些函数。最后将实现的函数动态的绑定到函数指针上,对使用接口的代码而言,它们再也不需要 switch - case 语句区分模式了,它们甚至无需关注模式,因为接口对此做了隐藏。就像在你的电脑上,文件系统是一个接口,我们只管用 write 函数存储参数,而不用理会存储介质,电脑上装的是硬盘就存硬盘上,装的是刻录机就存光盘上。

当理解了面向对象编程思想,理解了 SOLID 设计模式,我写代码的原则变成了只有以下 2 条:

  • 用测试驱动开发编写最简洁的代码。
  • 编写设备无关的代码

怎么算简洁?一个函数,你看上一遍,能拍着胸脯对自己说,它绝不会有 BUG ,这就是简洁。与之相反的,有一个函数,你看上半天,最后只能说,没有看到明显的 BUG,这就是复杂。

什么是设备无关的代码?不依赖具体硬件、不依赖底层实现,就像在应用层存储数据不必知道存哪种介质,只有这样,你才能更方便的更换存储介质。与之相反的,应用层中的函数一路调用下去,可以看到寄存器,那么应用层就跟硬件深度绑定了,任何硬件的改动,都要更改大量的代码。

相关文章:

书摘:C 嵌入式系统设计模式 02

本书的原著为:《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》,讲解的是嵌入式系统设计模式,是一本不可多得的好书。 本系列描述我对书中内容的理解。 结构化编程将软件组织成两个截然不同的…...

排序算法基本原理及实现1

📑打牌 : da pai ge的个人主页 🌤️个人专栏 : da pai ge的博客专栏 ☁️宝剑锋从磨砺出,梅花香自苦寒来 📑插入排序 &#x1f4…...

Unity 轨道展示系统(DollyMotion)

DollyMotion 🍱功能展示🥙使用💡设置路径点💡触发点位切换💡动态更新路径点💡事件触发💡设置路径💡设置移动方案固定速度方向最近路径方向 💡设置移动速度曲线 传送门 &a…...

优维低代码实践:搜索功能

优维低代码技术专栏,是一个全新的、技术为主的专栏,由优维技术委员会成员执笔,基于优维7年低代码技术研发及运维成果,主要介绍低代码相关的技术原理及架构逻辑,目的是给广大运维人提供一个技术交流与学习的平台。 优维…...

C# ReadOnlyRef Out

C# ReadOnly ReadOnly先看两种情况1.值类型2.引用类型 结论 Ref Out ReadOnly官方文档 ReadOnly 先看两种情况 1.值类型 当数据是值类型时,标记为Readonly时,如果再次设置值,会提示报错,无法分配到只读字段 public class A {pri…...

linux 服务 下 redis 安装和 启动

官网下载 https://redis.io/download/ 安装步骤: 1.安装redis 所需要的依赖 yum install -y gcc tcl2.上传安装包并解压,下载安装包,上传到/usr/local/src目录,解压 tar -zxvf redis-7.2.3.tat.gz进入安装目录,运行…...

ECharts与Excel的结合实战

引言&#xff1a;本文是一篇ECharts和Excel实战的记录。将Excel与ECharts产生火花&#xff0c;从Excel读取数据然后在ECharts上展示。 1.柱状图前端代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title…...

UDP的特点及应用场景

目录 UDP特点 应用场景 总结 User Datagram Protocol&#xff08;UDP&#xff0c;用户数据报协议&#xff09;是互联网协议套件中的一种传输层协议。与TCP不同&#xff0c;UDP是一种无连接的、不可靠的协议。 UDP特点 要知道UDP可以用来做什么&#xff0c;首先我们要知道它…...

Python开发——工具篇 Pycharm的相关配置,Python相关操作 持续更新

前言 本篇博客是python开发的工具篇相关&#xff0c;介绍pycharm的使用和相关配置&#xff0c;收录python的相关操作&#xff0c;比如如何启动jupyter。 目录 前言引出Pycharmpycharm如何不同等级日志显示不同颜色设置不同pycharm的python环境 Python操作如何启动Jupyter 总结…...

【深度学习】卷积神经网络结构组成与解释

卷积神经网络是以卷积层为主的深度网路结构&#xff0c;网络结构包括有卷积层、激活层、BN层、池化层、FC层、损失层等。卷积操作是对图像和滤波矩阵做内积&#xff08;元素相乘再求和&#xff09;的操作。 1. 卷积层 常见的卷积操作如下&#xff1a; 卷积操作解释图解标准卷…...

从源码解析Containerd容器启动流程

从源码解析Containerd容器启动流程 本文从源码的角度分析containerd容器启动流程以及相关功能的实现。 本篇containerd版本为v1.7.9。 更多文章访问 https://www.cyisme.top 本文从ctr run命令出发&#xff0c;分析containerd的容器启动流程。 ctr命令 查看文件cmd/ctr/comman…...

引迈-JNPF低代码项目技术栈介绍

从 2014 开始研发低代码前端渲染&#xff0c;到 2018 年开始研发后端低代码数据模型&#xff0c;发布了JNPF开发平台。 谨以此文针对 JNPF-JAVA-Cloud微服务 进行相关技术栈展示&#xff1a; 1. 项目前后端分离 前端采用Vue.js&#xff0c;这是一种流行的前端JavaScript框架&a…...

如何处理枚举类型(下)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 上一篇我们通过编写MyB…...

wsj0数据集原始文件.wv1.wv2转换成wav文件

文章目录 准备一、获取WSJO数据集二、安装sph2pipe三、转换代码四、结果展示 ​ 最近做语音分离实验需要用到wsj0-2mix数据集&#xff0c;但是从李宏毅语音分离教程里面获取的wsj0-2mix只有一部分。从网上获取到了完整的WSJO数据集后&#xff0c;由于原始的语音文件后缀是wv1或…...

Flask Session 登录认证模块

Flask 框架提供了强大的 Session 模块组件&#xff0c;为 Web 应用实现用户注册与登录系统提供了方便的机制。结合 Flask-WTF 表单组件&#xff0c;我们能够轻松地设计出用户友好且具备美观界面的注册和登录页面&#xff0c;使这一功能能够直接应用到我们的项目中。本文将深入探…...

【运维】hive 高可用详解: Hive MetaStore HA、hive server HA原理详解;hive高可用实现

文章目录 一. hive高可用原理说明1. Hive MetaStore HA2. hive server HA 二. hive高可用实现1. 配置2. beeline链接测试3. zookeeper相关操作 一. hive高可用原理说明 1. Hive MetaStore HA Hive元数据存储在MetaStore中&#xff0c;包括表的定义、分区、表的属性等信息。 hi…...

C#开发的OpenRA游戏之属性SelectionDecorations(13)

C#开发的OpenRA游戏之属性SelectionDecorations(13) 在前面分析SelectionDecorations属性类时,会发现它有下面这个属性: public class SelectionDecorations : SelectionDecorationsBase, IRender { readonly Interactable interactable; 它是定义了一个Interactabl…...

接手了一个外包开发的项目,我感觉我的头快要裂开了~

嗨&#xff0c;大家好&#xff0c;我是飘渺。 最近&#xff0c;我和小伙伴一起接手了一个由外包团队开发的微服务项目&#xff0c;这个项目采用了当前流行的Spring Cloud Alibaba微服务架构&#xff0c;并且是基于一个“大名鼎鼎”的微服务开源脚手架&#xff08;附带着模块代…...

git常规使用方法,常规命令

Git是一种分布式版本控制系统&#xff0c;它可以记录软件的历史版本&#xff0c;并提供了多人协作开发、版本回退等功能。以下是Git的基本使用方法&#xff1a; 安装Git&#xff1a;下载安装包并进行安装&#xff0c;安装完成后在命令行中输入 git --version 进行验证。 初始化…...

【JavaScript】3.3 JavaScript工具和库

文章目录 1. 包管理器2. 构建工具3. 测试框架4. JavaScript 库总结 在你的 JavaScript 开发之旅中&#xff0c;会遇到许多工具和库。这些工具和库可以帮助你更有效地编写和管理代码&#xff0c;提高工作效率。在本章节中&#xff0c;我们将探讨一些常见的 JavaScript 工具和库&…...

五年跨境人掏心窝:多SKU铺货,我终于不用“爆肝”了!

大家好&#xff0c;我是跨境小彭。时间过得真快&#xff0c;一转眼&#xff0c;入坑跨境电商已经五年了。从最早一个人一台电脑在出租屋里倒腾&#xff0c;到现在有了自己的小团队&#xff0c;这中间的辛酸泪&#xff0c;估计只有咱们圈内人懂。最近&#xff0c;后台收到不少刚…...

HAL_CAN_AddTxMessage硬件中断?原来是这个参数在捣鬼(附正确用法)

HAL_CAN_AddTxMessage硬件中断问题深度解析与实战指南 在STM32 HAL库开发中&#xff0c;CAN总线通信是工业控制、汽车电子等领域的核心功能模块。许多工程师在使用HAL_CAN_AddTxMessage函数时&#xff0c;都曾遭遇过神秘的硬件中断问题——代码看似正确&#xff0c;编译无警告&…...

MetalLB才是给Ingress这个老登做负重前行的那个男人棺

一、核心问题及解决方案&#xff08;按踩坑频率排序&#xff09; 问题 1&#xff1a;误删他人持有锁——最基础也最易犯的漏洞 成因&#xff1a;释放锁时未做身份校验&#xff0c;直接执行 DEL 命令删除键。典型场景&#xff1a;服务 A 持有锁后&#xff0c;业务逻辑耗时超过锁…...

Docker+SyncTV+cpolar三件套:手把手教你搭建私人同步影院(附固定域名技巧)

DockerSyncTVcpolar三件套&#xff1a;打造高可用私人同步影院实战指南 在数字娱乐需求日益个性化的今天&#xff0c;私人影院的搭建已经从单纯的本地播放升级为兼具社交属性的协同体验。想象一下&#xff0c;无论好友身处何地&#xff0c;都能实时同步观看你精选的影片&#x…...

Python实战:5种常用窗函数在音频信号处理中的对比与应用

Python实战&#xff1a;5种常用窗函数在音频信号处理中的对比与应用 当你第一次用麦克风录制一段钢琴曲时&#xff0c;可能会发现频谱图上出现了许多"不该存在"的频率成分。这种现象在专业术语中被称为频谱泄漏&#xff0c;而解决它的关键工具就是窗函数。作为音频处…...

实战复盘】游戏上市公司合同系统实施案例(六):被忽视的IT力量——为什么业务主导的项目更需要IT深度参与?

本文为《游戏上市公司合同系统实施案例》系列第六篇。 &#x1f449; &#xff08;一&#xff09;业务背景&#xff5c;&#xff08;二&#xff09;多维预算&#xff5c;&#xff08;三&#xff09;合同预警&#xff5c;&#xff08;四&#xff09;安全攻防&#xff5c;&#x…...

C# 面试高频题:装箱和拆箱是如何影响性能的?下

OCP原则 ocp指开闭原则&#xff0c;对扩展开放&#xff0c;对修改关闭。是七大原则中最基本的一个原则。 依赖倒置原则&#xff08;DIP&#xff09; 什么是依赖倒置原则 核心是面向接口编程、面向抽象编程&#xff0c; 不是面向具体编程。 依赖倒置原则的目的 降低耦合度&#…...

Scalatra 健康检查与监控:构建企业级可观测性系统

Scalatra 健康检查与监控&#xff1a;构建企业级可观测性系统 【免费下载链接】scalatra Tiny Scala high-performance, async web framework, inspired by Sinatra 项目地址: https://gitcode.com/gh_mirrors/sc/scalatra Scalatra 作为一款轻量级高性能的 Scala Web 框…...

ABB机器人编程避坑指南:从数据类型到运动指令的7个易错点

ABB机器人编程避坑指南&#xff1a;从数据类型到运动指令的7个易错点 第一次在RobotStudio里看到机器人因为数据类型错误突然停止时&#xff0c;我盯着报错信息足足愣了五分钟。这种经历在ABB机器人编程中并不罕见——从数据类型选择到运动指令参数设置&#xff0c;每个环节都可…...

拉普拉斯变换:从傅里叶到复频域的系统分析利器

1. 从傅里叶到拉普拉斯&#xff1a;为什么我们需要复频域&#xff1f; 第一次接触傅里叶变换时&#xff0c;你可能被它"时域转频域"的魔法惊艳到了——直到遇到一个尴尬问题&#xff1a;当信号不满足绝对可积条件时&#xff08;比如指数增长的信号e^t&#xff09;&am…...