0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ASSERT的定义及调试技巧

GReq_mcu168 来源:cg 2018-12-17 11:26 次阅读

技巧1:记住ASSERT的定义

对许多开发人员来说,断言是一个令人困惑的话题,因为它们的许多使用方式与其设计初衷背道而驰。我见到的最清晰的断言定义是这样的:

“断言是在程序某个特定点的一个布尔表达式,除非程序中有缺陷(Bug),否则它的值将为真。”

想要理解上述断言定义的开发人员应该留意下面三个要点:

·断言会评估一个表达式是真还是假

·断言是在代码中的某个点对系统状态的一种假设

·断言会验证系统假设,如果不为真,就表明代码中有一个缺陷

技巧2:使用ASSERT验证函数的先决条件

断言非常适合契约式设计环境,在这种环境中,开发人员非常清晰地定义了某个函数的先决条件。断言可以用来检查该函数的输入是否满足先决条件。就拿图1所示的代码片段为例:

图1:函数的先决条件

函数的State输入应该在定义的系统状态范围内。如果State不是有效的状态值,那么它就不是错误,而是缺陷!断言可以用来验证State是有效的假设,如图2所示:

图2:对函数先决条件应用断言

在State不小于最大值的事件中,断言表达式将被评估为假,程序于是将停止执行。停止程序执行可以让开发人员很容易马上看到哪里的代码出错,而不是过段时间以后才知道。

技巧3:使用ASSERT验证函数的后置条件

断言也能用来验证契约式设计环境中对某个函数输出的假设。例如,如果前面定义的System_StateSet函数返回SystemState变量,开发人员可以预计它也在期望的范围之内。断言可以用来对缺陷进行监视,如图3所示。

图3:对函数后置条件应用断言

开发人员在查看上述代码后可能会感到这些检查毫无意义。刚刚才设置好的SystemState怎么就会出现大于SYSTEM_STATE_MAX的值呢?答案是这确实不应该出现,然而有时候会莫名其妙地发生改变,也许是通过中断或并行线程,此时断言可以立即标志出这个缺陷。

技巧4:不要把ASSERT用于错误处理

在记住断言定义之后,开发人员应该切记:断言是用于检测缺陷的,不能用于错误处理。错误处理是设计用于响应错误的用户输入和意外的事件顺序的软件。错误在系统中预料是会发生的,但仅仅是因为有无效的输入而并不意味着代码中有缺陷。错误处理应该与缺陷寻找分开来。错误使用断言的一个典型例子是,在试图打开一个文件用于读取时去检查文件的指针,如图4所示。

图4:ASSERT的不当使用

读者可以清楚地看到,试图打开文件的结果与文件系统的状态和用户数据有关,而与代码中的缺陷一点关系也没有。开发人员应该编写错误处理程序,而不是用断言,以便在文件不存在时,错误处理程序可以用一些默认可用数据来创建它,以便后续代码继续操作。

技巧5:ASSERT仅对开发有意义,不能用于生产

开发ASSERT宏的原始意图是在开发过程中启用它,在后面生产时要禁用。可以用NDEBUG宏激活和禁用ASSERT。正确实施的断言在被禁用后应该对嵌入式系统基本没有影响。

问题是,如果测试是在断言启用的情况下进行的(为了捕捉任何缺陷,应该这样做),那么现在禁用断言将导致交付的产品与测试的产品处于不同的状态。断言确实会占用一些代码空间,但更重要的是,它们需要占用少量的时钟周期来评估它们的布尔表达式。禁用ASSERT可能对具有有限资源的裸机系统的执行时序产生很大影响,从而导致在生产系统中产生新的缺陷。开发团队需要判断是否值得冒关闭断言的风险。

一种替代方案是保留断言在激活状态,而将它们的输出重定向到一个系统日志。这样可以确保任何挥之不去的缺陷很容易被识别,而且能避免中止系统的运行,而中止系统可不是明智之举。

技巧6:不允许断言有副作用

ASSERT的默认实现允许开发人员包含一段可执行代码作为布尔表达式的一部分。举例来说,一个状态变量可以被实现为表达式的一部分并传递给ASSERT。但如果传递给ASSERT的表达式有副作用,也就是说,它会改变嵌入式系统的状态,那么禁用断言将改变系统的行为。开发人员应该确保他们的表达式没有副作用,否则他们需要冒险在系统中增加只针对产品代码唤醒的休眠时间缺陷。

技巧7:断言应该占代码的1%至3%

每个开发人员对于代码库(Code Base)中应该有多少个断言都有自己的主见。大家一致同意的一个数字是,代码库中的断言占比应该大于0。断言为开发人员提供了一种在代码库中发生缺陷的时刻发现它的好方法。调试是在开发嵌入式系统中最浪费时间并令人沮丧的事情之一。不管开发人员认可的占比是1%、3%还是5%,使用断言肯定对你有利,并会使开发嵌入式软件变得多少有些趣味。

技巧8:将断言用作可执行代码注释

断言可以生成极好的注释!编写出色的表达式可以确切地告诉开发人员在代码的某个给定点应该预料发生什么事情。开发人员应该做好他们断言的架构,帮助人们更清楚地理解系统中发生的事情,进而帮助减少缺陷。

小结

断言是一种出色的工具,但有太多的嵌入式软件开发人员忽视了这一工具。本文讨论的八个技巧只是如何正确使用断言的冰山一角。接下来读者就可以在测试平台中建立和开始使用断言,并研究它们在实际的嵌入式系统中是如何工作的。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7534

    浏览量

    128831
  • ASSERT
    +关注

    关注

    0

    文章

    17

    浏览量

    7136

原文标题:在C语言中用ASSERT调试的八个技巧

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言中assert的使用

    assert意思是断言,常用在程序的DEBUG版本中。
    发表于 07-21 14:51 518次阅读

    C语言assert(断言)简介

    assert的功能,条件为真,程序继续执行;如果断言为假(false),则程序终止。
    的头像 发表于 11-17 16:33 652次阅读
    C语言<b class='flag-5'>assert</b>(断言)简介

    如何在if和assert中做选择

    ;); abort(); } assert 是一个宏,不是一个函数在 assert.h 头文件中,有如下定义: #ifdef NDEBUG #define assert(c
    发表于 04-08 06:13

    RAW ASSERT

    assert 单独放一篇文章,可见是多么的重要。Raw os 提供了RAW_ASSERT 的接口。强烈建议在产品研发阶段打开assert 功能/*enable assert for
    发表于 02-27 14:09

    断言(ASSERT)的用法

    属于偶然性事件,又或者我们仅仅想测试一下,一些最坏情况是否发生,所以这里有了assert().   assert宏的原型定义assert.h中,其作用是如果它的条件返回错误,则终止程
    发表于 08-23 09:33

    如何使用assert

    头到文件尾,并且大多数情况下,我们要进行验证的假设,只是属于偶然性事件,又或者我们仅仅想测试一下,一些最坏情况是否发生,所以这里有了assert().  assert宏的原型定义assert
    发表于 04-05 11:05

    如何避免Xil_Assert系列宏导致的死循环

      在调试模式下,Xil_Assert系列宏会调用Xil_Assert来检查参数是否正常。如果不正常,缺省情况下,没有打印,会进入死循环。  通过调用void
    发表于 01-08 16:29

    怎样去使用assert_param函数呢

    assert_param是一个宏定义;在固件库中,它的作用就是检测传递给函数的参数是否是有效的参数。举例说明:  assert_param(IS_USART_ALL_PERIPH(USARTx));   这句代码用于检查参数US
    发表于 03-01 06:19

    怎样去解决RT-Thread系统中ASSERT失效的问题呢

    前言自己在使用动态内存过程中,重复rt_free一个指针,发现竟然没有出错!忽然发现自己的代码异常的健壮,不出现RT_ASSERT断言死机?经过软件调试,发现:自己关闭了 RT_ASSERT功能
    发表于 04-12 17:54

    多线程下ASSERT函数为什么会导致线程挂起呢

    线程运行ASSERT()失败。进入RTT中缺省的ASSERT()函数体中。RTT定义ASSERT失败的例程是一个无限while()循环,循环体中没有任何处理。如果是有main()函数中
    发表于 09-27 10:10

    MFC中ASSERT常见用法

      在C++的消息公告板上经常可以看到出现ASSERT错误的求助信息。虽然这通常是希望消除ASSERT错误的帮助请求,但是几乎所有的求助者都认为ASSERT本身是罪恶的。我完全能理解一
    发表于 09-07 15:55 19次下载

    STM32库函数中assert_param语句的用法解析

    assert_param语句是用于程序开发的时候,调试用的检测语句。默认是不开启的,你可以无视它的存在。但是,当你在调试程序的时候,可以打开这个检测机制,调试完了再关闭。
    发表于 11-28 16:03 1.6w次阅读
    STM32库函数中<b class='flag-5'>assert</b>_param语句的用法解析

    怎么理解Assert中的断言语句?

    为什么项目中的代码需要有Assert断言语句?
    的头像 发表于 03-03 14:12 2476次阅读

    如何避免Xil_Assert系列宏导致的死循环的情况

    调试模式下,Xil_Assert系列宏会调用Xil_Assert来检查参数是否正常。如果不正常,缺省情况下,没有打印,会进入死循环。 通过调用void Xil_AssertSetCallback
    的头像 发表于 12-02 16:20 3826次阅读
    如何避免Xil_<b class='flag-5'>Assert</b>系列宏导致的死循环的情况

    【C语言进阶】利用assert高效排查你的C程序

    【C语言进阶】利用assert高效排查你的C程序
    的头像 发表于 08-31 13:27 1751次阅读