编程精粹—— Microsoft 编写优质无错 C 程序秘诀 02:设计并使用断言

这是一本老书,作者 Steve Maguire 在微软工作期间写了这本书,英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字,英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》,这本书主要讨论如何编写健壮、高质量的代码。作者在书中分享了许多实际编程的技巧和经验,旨在帮助开发人员避免常见的编程错误,提高代码的可靠性和可维护性。


不记录,等于没读。本文记录书中第二章内容:设计并使用断言。


一个好的开发策略是维护程序的两个版本:发布版本调试版本。通过在调试版本中使用 断言 语句,你可以检测以下错误:

  • 错误的函数参数
  • 未定义行为
  • 其他程序员做出的错误假设
  • 不知何故出现的不可能条件

仅在调试模式下启用的备用算法有助于验证函数结果和函数中所使用算法的正确性。

第一章介绍了一些方法,以便检测到更多的错误,比如启用所有可选的编译器警告、使用使用语法和可移植性检查工具等。这些措施当然是好的,这是这些措施只能查出所有错误的一小部分。举一个例子:

strCopy = memcpy(malloc(length), str, length);

这句代码在多数情况下都会工作良好,直到 malloc 函数调用失败。当 malloc 失败时,就会给 memcpy 函数返回 NULL 指针,从而出错。

编译器检查不出这种错误,同样,编译器也检查不出算法错误,无法验证程序员所作的假设。寻找这种错误非常艰苦,但如果在实现 memcpy 函数时,检查一下参数是否有效,就可以自动捕获这个错误。

聪明的程序员将调试代码隐藏在断言 assert。断言的好处是用户在错误发生时,可以自动地把它们检查出来。

assert 是一个宏,如果其参数的计算结果为假,就中止调用程序的执行。

assert不应该产生其它副作用。因此assert应该为宏而不是函数,因为函数调用会引起不期望的内存或代码交换。

使用断言对函数参数进行确认

比如前面提到的 memcpy 函数,我们可以使用断言进行参数确认,代码如下:

void memcpy(void* pvTo, void* pvFrom, size_t size) {void* pbTo = (byte*)pvTo;void* pbFrom = (byte*)pvFrom;assert(pvTo != NULL && pvFrom != NULL);		//<--- 使用断言while(size-->0)*pbTo++ == *pbFrom++;return(pvTo);
}

这样,当给参数 pvTopvFrom 传递 NULL 时,就会触发断言,从而自动的发现程序代码错误。

使用断言避免未定义行为

要从程序中删除未定义的特性或者在程序中使用断言来检查出未定义特性的非法使用

使用库函数memcpy时,如果在存储空间相互重叠的对象之间进行了拷贝,结果是未定义的。

可以使用断言来进行重叠检查:

ASSERT(pbTo >= pbFrom + size || pbFrom >= pbTo + size);

假如你之前从来没有见过重叠检查,当这个断言捕获到错误时,你能看出来它是什么意思吗?

断言捕获了一个错误,我们却不知道断言的作用,没有什么比这件事更令人沮丧了。

如果搞不清楚相应断言检查的是什么,就很难知道错误是出现在程序中,还是出现在断言中。

解决这个问题的方法是:给不够清晰的断言加上注解

不要浪费别人的时间——详细说明不清晰的断言

一个人在穿过森林时,看到树上钉着一块大牌子,上面写着两个红色大字:“危险”。但危险到底是什么?

除非告诉人们危险是什么或者危险非常明显,否则这个牌子起不到提高人们警觉的作用,人们会忽视牌子上的警告。

同样,程序员不理解的断言也会被忽视。

利用断言消除隐式假设

如果假设long占用4个字节,可以使用以下断言来检查假设是否正确:

ASSERT(sizeof(long) == 4);

在编写函数时,要进行反复的思考,并且自问:“我打算做哪些假设?”

一旦确定了相应的假设,就要使用断言对所做的假设进行检验,或者重新编写代码去掉相应的假设。

另外,还要问:“这个程序中最可能出错的是什么,怎样才能自动地查出相应的错误?”努力编写出能够尽早查出错误的测试程序。

利用断言检查不可能发生的情况

断言是检查那些在正常情况下绝不应该发生的情况,而不是用于检查错误。换句话说,断言是防止程序员失误的一种手段,绝不要把必须执行的代码放入断言中

比如函数参数不可能超过某个范围,可使用断言来验证;malloc 函数返回是否为 NULL 就不能使用断言来检查,判断是否为 NULL 是错误检查的一部分;

比如一个解压缩协议规定:如果遇到0xA5,那么0xA5后面必须是 字符压缩序列,字符压缩序列占用两个字节,第一个字节表示 压缩的字符,第二个字节表示 字符重复的个数

我们认为 字符序列 只能有两种情况:

  1. 压缩的字符是 0xA5,字符重复个数固定为1
  2. 压缩的字符不是 0xA5,字符重复个数必须大于等于4

则可以使用以下断言对规则进行验证:

#define REPEAT_CODE    0xA5
//...
ASSERT( size>=4 || (size==1 && b==bRepeatCode) )

如果这一断言失败说明内容不对或者字符压缩程序中有错误。无论哪种情况都是错误,而且是不用断言就很难发现的错误。

利用断言发现静默的异常行为

防错性程序设计常常被誉为有较好的编码风格,但它却隐瞒了绝不应该发生的错误。

核反应堆堆芯过热,程序自动地向堆芯灌水、插入冷却棒或者做其它能让堆芯冷却下来的方法。只要程序已经控制了事态,就不会向有关人员报警。

这和我们写的防错程序很像,当某些意料不到的事情发生时,程序只进行静默处理。

但是堆芯不会无缘无故地出现过热现象,一定是发生了某种不同寻常的事情,才会引起这一故障。但在值班人员眼里,核反应堆一切正常,错误被隐瞒了。

即便如此,防错性程序仍然有它的价值。我们希望在进行防错性程序设计时,不要隐瞒错误

一方面一如既往地利用防错性程序设计进行编码,另一方面在事情变糟的情况下利用断言进行报警

核反应堆堆芯过热,立即向工作人员发出警报。同时,程序自动地向堆芯灌水、插入冷却棒或者做其它能让堆芯冷却下来的方法。

如果使用到防错性程序设计,在编码之前都要问自己:**“在进行防错性程序设计时,程序中隐瞒错误了吗?”**如果答案是肯定的,就要在程序中加上相应的断言,以对这些错误进行报警。


有很多书都有讲解断言,有很多开源代码都在使用断言。在工作了几年之后,我对断言也有了一些见解,我将它们写在了《随想012:断言》 这篇文章中,推荐阅读。






每一份打赏,都是对创作者劳动的肯定与回报。
千金难买知识,但可以买好多奶粉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/854765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6spark期末复习

1)var a:Double5;var b:Int7;那么print(a*b) 2) var a:Int5; var bif(a>6) 7 println(b) 3)var a:Int16; var b:Int13; var cif(a>b) 5 else 7; println(c) 4. object TestDemo { print("B") def main(args: Array[String]): Unit { } } 5 def mai…

JeecgFlow排他网关演示

排他网关概念理解 排他网关&#xff0c;也称为异或(XOR)网关&#xff0c;用于流程中实现分支决策建模。排他网关需要搭配条件顺序流使用。 当流程流转到排他网关时&#xff0c;所有流程顺序流都是会顺序求解&#xff0c; 其中第一条条件为true的顺序流会被选中(当有多条顺序流都…

澳汰尔(Altair)3D 打印部件设计仿真——打造高效的增材制造设计

借助 Inspire Print3D&#xff0c;可加速创新、结构高效的 3D 打印部件的创建、优化和研究&#xff0c;提供快速准确的工具集&#xff0c;可用于实现选择性激光熔融 (SLM) 部件的设计和过程仿真。 工程师可以快速了解影响可制造性的工艺或设计变更&#xff0c;然后将部件和支撑…

JWT的优势

1、无状态&#xff1a; 2、有效避免了 CSRF 攻击&#xff1a;CSRF攻击&#xff0c;采用的是cookie进行攻击的&#xff1b;也避免XSS攻击&#xff0c;XSS采用的是js脚本进行攻击。 3、适合移动端应用&#xff1a;移动端没有cookie&#xff0c;jwt 4、单点登录友好&#xff1a…

SoC设计更重要的是IP管理

对于大多数片上系统&#xff08;SoC&#xff09;设计来说&#xff0c;最关键的任务不是RTL编码&#xff0c;甚至不是创建芯片架构。今天&#xff0c;SoC的设计主要使用来自多个供应商的各种IP块。这使得管理硅IP成为SoC设计过程中的主要任务。 一般来说&#xff0c;新编写的RTL…

Swift Combine — JUST Publisher

之前文章介绍的Publisher都是可以连续发送数据的&#xff0c;Subscriber也可以一直接收数据&#xff0c;除非收到了finished或者error而结束。而JUST Publisher则不同&#xff0c;它只向每个订阅者发送一次输出&#xff0c;然后结束。 一起来看一下下面的代码。 class JustVi…

从0到1:手动测试迈向自动化——手机web应用的自动化测试工具

引言&#xff1a; 在当今移动互联网时代&#xff0c;手机web应用已经成为人们生活中不可或缺的一部分。为了保证手机web应用的质量和稳定性&#xff0c;自动化测试工具变得十分重要。本文将介绍手机web应用自动化测试工具的选择和使用&#xff0c;提供一份超详细且规范的指南&a…

GPT3.5的PPO目标函数怎么来的:From PPO to PPO-ptx

给定当前优化的大模型 π \pi π&#xff0c;以及SFT模型 π S F T \pi_{SFT} πSFT​ 原始优化目标为: max ⁡ E ( s , a ) ∼ R L [ π ( s , a ) π S F T ( s , a ) A π S F T ( s , a ) ] \max E_{(s,a)\sim RL}[\frac{\pi(s,a)}{\pi_{SFT}(s,a)}A^{\pi_{SFT}}(s,a)] m…

力扣668.乘法表中第k小的数

力扣668.乘法表中第k小的数 二分查找 是否有k个比mid小的数 class Solution {public:int findKthNumber(int m, int n, int k) {auto check [&](int mid) -> bool{int res0;int row 1,col n;while(row < m){if(row * col < mid){res col;if(res > k) re…

软件测试全面指南:提升软件质量的系统流程

一、引言 随着软件行业的飞速发展&#xff0c;确保软件质量、稳定性和用户体验已成为企业竞争的关键。本文档旨在为测试团队提供一套全面的软件测试指南&#xff0c;通过规范测试用例管理、功能测试、接口测试、性能测试及缺陷管理等流程&#xff0c;助力测试团队实现高效、系统…

重构大学数学基础_week05_雅各比矩阵与雅各比行列式

这周来讲一下雅各比矩阵和雅各比行列式。 多元函数的局部线性属性 首先我们来回顾一下向量函数&#xff0c;就是我们输入一个向量&#xff0c;输出也是一个向量&#xff0c;我们假设现在有一个向量函数 这个函数意思就是在说&#xff0c;我们在原来的平面上有一个向量(x,y),经…

美团Meitu前端一面,期望27K

面经哥只做互联网社招面试经历分享&#xff0c;关注我&#xff0c;每日推送精选面经&#xff0c;面试前&#xff0c;先找面经哥 1、做的主要是什么项目&#xff0c;桌面端的吗&#xff1f; 2、用的主要是什么技术栈&#xff1f;vue有了解吗&#xff1f; 3、移动端开发一般怎么…

使用Ventoy制作U盘启动安装系统

简介 Ventoy是一个制作可启动U盘的开源工具。 无需反复地格式化U盘。你只要制作一次U盘启动盘&#xff0c;后面你只需要把 ISO/WIM/IMG/VHD(x)/EFI 等类型的系统镜像文件直接拷贝到U盘里面就可以启动了&#xff0c;无需其他操作。可以一次性拷贝很多个不同类型的镜像文件&…

vue+element-plus完美实现跨境电商商城网站

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.中英文样式切换 4.金钱类型切换 5.商品详情 6.购物车 7.登录 ​编辑 8.注册 9.个人中心 三、源码实现 1.项目依赖package.json 2.项目启动 3.购物车页面 四、总结 一、项目介绍 本项目在线预览&am…

深入解析Python闭包:定义、实例与应用

深入解析Python闭包&#xff1a;定义、实例与应用 引言 在Python编程中&#xff0c;闭包&#xff08;Closure&#xff09;是一个强大而实用的概念。它允许函数记住并访问其词法作用域&#xff08;lexical scope&#xff09;&#xff0c;即使在函数执行完毕后&#xff0c;其内…

提拔你,还是干掉你,从来不是看技术

有读者问我&#xff0c;技术人员工作5~10年就逐渐拉开了差距&#xff0c;这背后的原因是什么&#xff1f;思考片刻后&#xff0c;我回答&#xff1a;是底层能力。 K哥有20年职场经验&#xff0c;从程序员到技术高管一路走来&#xff0c;我总结了技术人员最重要的一些认知和底层…

如何通过小猪APP分发轻松实现Web封装APP

你有没有想过将你的网站或者Web应用变成一个真正的APP&#xff1f;这听起来可能有点复杂&#xff0c;但其实在今天的技术环境下&#xff0c;这已经变得非常简单了。特别是有了像小猪APP分发这样的工具&#xff0c;你可以轻松地将你的Web应用封装成一个APP。 为什么要将Web应用封…

Python 学习 第二册 第15章 Python和Web

----用教授的方法学习。 目录 15.1 屏幕抓取 15.1.1 Tidy 和 XHTML 解析 15.1.2 Beautiful Soup 15.2 使用 CGI 创建动态网页 15.2.1 第一步:准备 Web 服务器 15.2.2 第二步:添加#!行 15.2.3 第三步:设置文件权限 15.2.4 简单的 CGI 脚本 15.2.5 使用 cgitb 进行调…

【大数据·hadoop】项目实践:IDEA实现WordCount词频统计项目

一、环境准备 1.1&#xff1a;在ubuntu上安装idea 我们知道&#xff0c;在hdfs分布式系统中&#xff0c;MapReduce这部分程序是需要用户自己开发&#xff0c;我们在ubuntu上安装idea也是为了开发wordcount所需的Map和Reduce程序&#xff0c;最后打包&#xff0c;上传到hdfs上…

Python面试宝典:Python中与常用的机器学习库相关的面试笔试题(1000加面试笔试题助你轻松捕获大厂Offer)

Python面试宝典:1000加python面试题助你轻松捕获大厂Offer【第二部分:Python高级特性:第二十六章:Python与数据科学:第三节:Python中常用的机器学习库】 第二十六章:Python与数据科学第三节:Python中常用的机器学习库1. Scikit-learn2. TensorFlow3. PyTorch4. Keras5.…