当前位置:首页 > 公众号精选 > 华清远见武汉中心
[导读]高端IT就业培训专家-15年口碑积累,20万名研发工程师从这里走出         很多时候,我们因为关注最终的结果,而总是忽略其它的情况。所以我们写的代码并不是那么的健壮。这篇文章属于程序员内功修炼,值得一看。写代码的时候,有几个阶段可以参考一下(鱼鹰经


高端IT就业培训专家-15年口碑积累,20万名研发工程师从这里走出



        很多时候,我们因为关注最终的结果,而总是忽略其它的情况。所以我们写的代码并不是那么的健壮。这篇文章属于程序员内功修炼,值得一看。写代码的时候,有几个阶段可以参考一下(鱼鹰经历并总结):



 阶段一 

只要最终的结果


        处于这个阶段的一般都是初学者,眼里只有一个目标,那就是程序运行成功,从不考虑其他因素。比如一个简单的 SPI 驱动程序,最终的目标只要一个,通信成功。所以当需要延时时就会采用死等方式等待结果,而不会考虑其他可能出现的结果,比如因为某种原因导致引脚电平被持续一个电平不变,导致死循环;比如因为你的延时,导致其他人功能无法及时处理。这个时候的思考总是过于理想化,不是因为自己太理想,太乐观,而是因为没有足够的经历告诉你,这样写是有问题的。因为没有经历过,所以初学者也就考虑不了那么多,所以你看初学者的代码会很简单,是一条直线,逻辑很清晰,没有岔路。



 阶段二 

做一些常见的异常处理


        随着经历越多(不管是网上看到的还是自己经历的),渐渐地,自己的代码变得多了一些,功能还是那个功能,只是这时候的你考虑的更多,更全面,你渐渐的增加了各种异常处理。比如你不再使用死等方式延时,而是增加了一个等待时间的超时处理;又比如你写的程序不再只有if里面的内容(条件为真),还有else(条件为假)。这个时候的你眼里不再只有最终的结果,还有在运行过程中可能出现的其他情况,并且会对这些情况做处理。



 阶段三 

怀疑一切


        这个阶段的你不再相信任何东西了,即使它是那么的可靠。你总是在函数开始处检查传入的参数(如果有的话),判断指针是否为空,判断数据是否在需要的范围内,等等。总是在使用指针、数组的时候小心翼翼,深怕一不小心就越界了,而这种BUG只有经历的人才懂到底有多难查。总是在异常的地方做出一些动作,如返回错误代号、如打印错误消息等。不管怎样,在出现问题后,你总是能够快速的定位问题,而这,得益于你对异常的处理。



 阶段四 

做好善后工作


        阶段三可能让你很快的定位问题,但是一旦出现问题,程序还是无法正常执行下去,比如申请的资源(内存、信号量等)没释放,又比如关闭的中断在异常后未重新打开等等。所以异常处理代码除了能很快定位BUG外,还要做好善后处理,这样才能让程序健壮的一直运行下去。

        鱼鹰曾在《代码写完了,你要花多少时间测试?》一文中介绍了一些调试方法,今天,继续更深入的探讨。


(uCOS II代码片段)
          很多人其实不明白,为什么一定要在函数开头检查参数,这不是很浪费时间的吗(从上面可以看到,参数检查有时候比真正需要执行的代码还要多)? 不说指针,就说一些普通变量,为什么要检查? 检查的意义又在哪里?

 浪费时间?
        首先说说浪费时间的问题,确实,因为总是在开头检查参数,会浪费CPU的时间(鱼鹰一开始也非常不喜欢),但是当你经历了各种难查的BUG之后,你会发现,这点时间还是浪费的起。 而事实上,软件开发一般都会有两个版本,一个是Debug版本,一个是Release版本,只要通过宏进行控制,那么就可以在稳定之后,不再检查这些参数了。 但是有些重要的数据,即使稳定了,也不能放弃对它的检查,否则一旦出现问题,就是灾难。 所以在检查时,还要考虑这些检查是否在Release版本也是需要的,即按重要性分开检查。

 为什么要检查?检查的意义又在哪里?
        这些检查就像是 函数的护城河 ,保证即使参数错误,也不会导致异常问题,比如数组越界,计算出错等。 那么我们要问了,参数怎么会错误,代码都是固定死的,有经验的都知道,参数是保存在 栈或寄存器 的,怎么会错呢? 你说内存数据保存时有问题? 保存时为1,读出时为0? 别逗了,如果真是这样,那还怎么玩? 程序根本没办法跑好吧(遇到强干扰可能会出现这种情况,甚至可能CPU执行流程都是乱的,最终只能重启,这个鱼鹰倒还没遇到过)。 我们可以认为存在RAM和FLASH的数据在存储和读取方面没有问题,那么又是什么导致了参数出错呢?

 栈溢出 
        前面说过,参数有可能保存在栈里面,如果有些栈溢出了,参数被破坏也就可以理解了。(关于栈,可参考笔记《 今天,你的栈溢出了吗? 》)

 数组越界、野指针等指针问题 
        一旦越界,那么产生的破坏力不可想象。 所谓越界,就是修改了不属于你的变量。 比如一个数组,你操作了数组外的数据(不管是数组前面的还是数组后面的)。 而越界根据位置又可以分为三种情况。


第一种, 栈(stack) ,比如你在栈里面申请了一个数组,越界了,那么修改的就是栈内容。
第二种: 堆(Heap) 。你通过malloc申请的内存,如果操作失误,那么就会修改不属于你的空间。
第三种。 全局变量(data) 。如果操作失误,也会出现问题。

        其实, 越界这种问题不一定就只会修改这些单独的区域,可能是两个区、三个区一起修改了 ,毕竟指针可不管修改的地址到底属于哪个区,还有一种是 野指针 导致的异常操作,那么它修改的位置只有鬼知道了(鬼好像不懂程序)。 比如你申请了一个数组,通过传入的参数修改数据,如果不限制参数大小,你确定它不会把你数组后所有的内存都给清零?


        如果硬要为上面三种情况划分处理难度等级,那么最容易也最快解决的就是全局变量的修改,为什么?因为地址比较固定,而ARM内核有神器处理这种情况,如果出现概率高的话,一查一个准,所以鱼鹰都不怎么苦恼这种问题。
        最难解决的是堆的修改,这种问题比栈更难找。原因就在于, 内存动态申请和释放 ,可能这次修改的是这个位置,没出现问题,下次修改另一个地址,就出现了问题,这种是最难查的。而栈的空间一般不会太大,而且他的存取都是有规律的,要稍微好查一些。
        可能你会问,参数会保存在寄存器里面,那么寄存器的数据有可能被异常修改吗? 异常修改的可能性很小,因为对于C语言而言,寄存器是透明的,用户很难操作这个。 但是,虽然说参数传入之后被修改的可能性很小,但是传入前修改的可能性还是很大的,比如你传入的参数是一个全局变量,那么这个全局变量是可能被异常修改的啊! 所以,参数检查,是一个健壮程序必须要有的,这是防止产生重大问题最重要的护城河。 而越早检查出问题,那么越容易定位问
        蝴蝶效应大家都知道,千里之堤毁于蚁穴大家也知道,用在程序里面也是很合适的。 可能你会说,我对自己有信心,我的技术杠杠的,绝对不会出问题。 真的是这样吗?


 01 
时间久了自己都忘了

        工作时,常常完成了一个项目,下一个项目马上来了,如果老项目需要维护,不需要一两年,只要一两个月,如果你没有参数检查、异常处理的好习惯,一旦你修改了代码,那么很可能因为某些疏忽,导致难以发现的BUG,而解决这些BUG的时间,比你写这些异常处理代码更多。 但是在你刚开始写这份代码的时候,因为思路清晰,考虑的比较多,有哪些异常很清楚,那么很容易写出那些异常处理代码。 比如鱼鹰去年写了一份通过位绑定地址,批量配置引脚的时钟、寄存器信息的代码,那么今年再复用代码的时候,因为自己的疏忽,很可能需要大量的时间解决BUG,那我写这份代码的意义就不存在了(写这份代码就是为了在标准库中通过端口和引脚号快速配置引脚),而如果说,一旦因为疏忽导致的问题,程序会自动帮你检查,那么解决问题就很快了。


 02 
维护

        不管是别人维护,还是自己维护,当项目需要更改需求时,如果因为某些疏忽,导致了BUG,那么解决起来费时费力,而且即使你这次解决了,难道下次还要重蹈覆辙吗?


 03 
合作开发

        一个项目可能不是一个人完成的,而是多人合作。而每个人的水平有高有低, 你敢说别人不会写出有问题的代码?你敢说自己一定不会写出有问题的代码? 而且即使别人没有写出BUG,但因为某些原因,需要修改或屏蔽你的代码,如果你的代码能自动提醒出这些异常,那么定位问题也就不难了。 而鱼鹰为什么写代码的时间会比测试长,除了掌握大量的调试技巧外,就是因为在写的时候,会考虑很多,并且这些考虑,大部分会以代码的形式存在,少量的会以注释或者#warning、#error 形式存在,而其中,最好的方式是代码形式,因为它能保证程序正常运行,即使不能正常运行,也应该打印消息以提醒用户问题在何处。 所以,鱼鹰总是很庆幸自己当初花了不少时间去写异常处理代码,而这些代码,如果需要事后弥补的话,相信花的时间会更多(定位问题、回想当初自己如何思考、补充异常处理代码,这些都要时间)。


END

免责声明:整理文章为传播相关技术,版权归原作者所有

如有侵权,请联系删除




  专业始于专注  

  卓识始于远见  




# 往期干货 #

点击下方图片即刻前往





   瞅一瞅看一看 ↘ 

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

2023年10月18日,中国在第三届“一带一路”国际合作高峰论坛期间发布《全球人工智能治理倡议》,围绕人工智能发展、安全、治理三方面系统阐述了人工智能治理中国方案。

关键字: 人工智能 大模型 代码

我们看到这么多的安全问题,部分原因在于我们对待安全的方式:安全性通常被认为是事后考虑的问题,是在开发结束时才添加到设备上的东西。然而,复杂的系统,尤其是嵌入式系统,有一个很大的攻击面,这让攻击者有机可乘,能够在“盔甲”上...

关键字: 代码 嵌入式系统 软件漏洞

新富人群财务需求多元发展,投顾服务迎来新机遇 上海2023年9月20日 /美通社/ -- 2023年9月19日,上海交通大学上海高级金融学院(高金)与全球领先的金融服务机构嘉信理财(Charles Schwab)联合发...

关键字: BSP ADVANCED INA 代码

北京2023年9月14日 /美通社/ -- 生物医药高科技公司诺诚健华(港交所代码:09969;上交所代码:688428)今日宣布,新型蛋白酪氨酸磷酸酶SHP2变构抑制剂ICP-189联用针对表皮生长因子受体(EGFR)...

关键字: IC HP 代码 ARMA

上海2023年9月1日 /美通社/ -- 2023上半年,安集科技(股票代码:688019)市场拓展规划成效显现,营业收入稳健增长。 全球半导体产业挑战持续存在的情形下,安集科技秉承发扬"克难攻坚,敢打硬...

关键字: 安集科技 BSP 代码 半导体材料

国际酒店运营商升级其在线支付功能 上海2023年8月28日 /美通社/ -- 加拿大金融科技公司Nuvei Corporation(以下简称“Nuvei”或“公司”)(纳斯达克代码:NVEI)(多伦多证券交易所代码:N...

关键字: 代码 IP SE 纳斯达克

2023年上半年收入7.459亿元 同比增长5.1% 毛利率水平上升 海外收入同比增长65.4% 香港2023年8月22日 /美通社/ -- 金邦达宝嘉控股有限公司及其附属公司(以下合称「金邦达」、「...

关键字: 数字化 代码 嵌入式软件 COM

我们经常对正在进行数字化转型的亚马逊云科技客户建议,将云迁移视为其数字化转型的一部分,数字化转型本身必须由业务成果驱动。其中治理计划的有效性决定了云迁移和数字化转型的成功与否。数字化转型中的云迁移总有结束的时候,但是如果...

关键字: 代码 数字化 云服务

广州及苏州生产基地产品均实现"出口"零突破 北京2023年8月21日 /美通社/ -- 百济神州(纳斯达克代码:BGNE;香港联交所代码:06160;上交所代码:688235)是一家全球性生物科技公...

关键字: 神州 代码 TI PD

近年来,国内电子公司和芯片设计企业大举进攻汽车、医疗和工业等高可靠应用(mission-critical)领域,为自己找到了摆脱红海的新领域。但是高可靠应用多数都需要功能安全认证,在许多行业在诸如汽车、航空电子、医疗和工...

关键字: 代码 代码分析工具
关闭
关闭