草庐IT

断言(assert)的用法

runoob 2023-03-28 原文

我一直以为 assert 仅仅是个报错函数,事实上,它居然是个宏,并且作用并非"报错"。

在经过对其进行一定了解之后,发现 assert() 的用法像是一种"契约式编程",在我的理解中,其表达的意思就是,程序在我的假设条件下,能够正常良好的运作,其实就相当于一个 if 语句:

if(假设成立)
{
     程序正常运行;
}
else
{
      报错&&终止程序!(避免由程序运行引起更大的错误)  
}

但是这样写的话,就会有无数个 if 语句,甚至会出现,一个 if 语句的括号从文件头到文件尾,并且大多数情况下,我们要进行验证的假设,只是属于偶然性事件,又或者我们仅仅想测试一下,一些最坏情况是否发生,所以这里有了 assert()。

assert 宏的原型定义在 assert.h 中,其作用是如果它的条件返回错误,则终止程序执行。

#include "assert.h" 
void assert( int expression );

assert 的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行。

使用 assert 的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。

在调试结束后,可以通过在包含 #include 的语句之前插入 #define NDEBUG 来禁用 assert 调用,示例代码如下:

#include 
#define NDEBUG 
#include

用法总结与注意事项

1)在函数开始处检验传入参数的合法性

如:

int resetBufferSize(int nNewSize) 
{ 
//功能:改变缓冲区大小, 
//参数:nNewSize 缓冲区新长度 
//返回值:缓冲区当前长度 
//说明:保持原信息内容不变 nNewSize<=0表示清除缓冲区 
assert(nNewSize >= 0); 
assert(nNewSize <= MAX_BUFFER_SIZE); 
 
... 
}

2)每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败

     

不好:

assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize); 
    

好:

assert(nOffset >= 0); 
assert(nOffset+nSize <= m_nInfomationSize); 

3)不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题

错误: assert(i++ <>

这是因为如果出错,比如在执行之前i=100,那么这条语句就不会执行,那么i++这条命令就没有执行。

正确:

assert(i < 100)
i++; 

4)assert和后面的语句应空一行,以形成逻辑和视觉上的一致感

  

5)有的地方,assert不能代替条件过滤   

  

程序一般分为Debug 版本和Release 版本,Debug 版本用于内部调试,Release 版本发行给用户使用。断言assert 是仅在Debug 版本起作用的宏,它用于检查"不应该"发生的情况。以下是一个内存复制程序,在运行过程中,如果assert 的参数为假,那么程序就会中止(一般地还会出现提示对话,说明在什么地方引发了assert)。

以下是使用断言的几个原则:

  • (1)使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是必然存在的并且是一定要作出处理的。
  • (2)使用断言对函数的参数进行确认。
  • (3)在编写函数时,要进行反复的考查,并且自问:"我打算做哪些假定?"一旦确定了的假定,就要使用断言对假定进行检查。
  • (4)一般教科书都鼓励程序员们进行防错性的程序设计,但要记住这种编程风格会隐瞒错误。当进行防错性编程时,如果"不可能发生"的事情的确发生了,则要使用断言进行报警。

ASSERT ()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。

ASSERT 只有在 Debug 版本中才有效,如果编译为 Release 版本则被忽略。

原文地址:https://www.cnblogs.com/thisway/p/5558914.html

有关断言(assert)的用法的更多相关文章

  1. ruby - 有人可以解释一下在 Ruby 中注入(inject)的真实、通俗易懂的用法吗? - 2

    我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有

  2. ruby - 为什么 Minitest 的 assert_raises 在这种情况下没有按预期工作? - 2

    我正在尝试使用ActionControllerbugreporttemplate解决Rails中的一个奇怪行为.为了记录,这是模板中的Controller:classTestController我已经为缺失的Action添加了一条路线:routes.drawdoget'/'=>'test#index'get'/missing'=>'test#missing'end并且我试图断言AbstractController::ActionNotFound在遵循该路线时被引发:classBugTest预期行为:绿色测试。实际行为:#Runningtests:D,[2014-04-24T09:17:

  3. ruby - 使用法拉第上传文件 - 2

    我在尝试使用Faraday将文件上传到网络服务时遇到问题。我的代码:conn=Faraday.new('http://myapi')do|f|f.request:multipartendpayload={:file=>Faraday::UploadIO.new('...','image/jpeg')}conn.post('/',payload)尝试发布后似乎没有任何反应。当我检查响应时this是我所看到的:#:post,:body=>#,#,@opts={}>,#],@index=0>>,#>],@ios=[#,#,@opts={}>,#],@index=0>,#],@index=0>

  4. ruby - rspec: raise_error 用法来匹配错误信息 - 2

    我使用raise(ConfigurationError.new(msg))引发错误我试着用rspec测试一下:expect{Base.configuration.username}.toraise_error(ConfigurationError,message)但这行不通。我该如何测试呢?目标是匹配message。 最佳答案 您可以使用正则表达式匹配错误消息:it{expect{Foo.bar}.toraise_error(NoMethodError,/private/)}这将检查NoMethodError是否由privateme

  5. 【ChatGPT】ChatGPT 的 N 种用法 - 2

    目录ChatGPT简介技术原理应用未来发展ChatGPT的10 种用法ChatGPT简介ChatGPT是一种基于深度学习的大型语言模型,由OpenAI公司开发。技术原理GPT是GenerativePre-trainedTransformer的缩写,意为生成式预训练变压器。它的技术原理是使用了一个基于注意力机制的变压器(Trans

  6. 【RuntimeError: CUDA error: device-side assert triggered】问题与解决 - 2

    RuntimeError:CUDAerror:device-sideasserttriggered问题描述解决思路发现问题:总结问题描述当我在调试模型的时候,出现了如下的问题/opt/conda/conda-bld/pytorch_1656352465323/work/aten/src/ATen/native/cuda/IndexKernel.cu:91:operator():block:[5,0,0],thread:[63,0,0]Assertion`index>=-sizes[i]&&index通过提示信息可以知道是个数组越界的问题。但是如图一中第二行话所说这个问题可能并不出在提示的代码段

  7. ruby-on-rails - 如何扩展 Ruby Test::Unit 断言以包含 assert_false? - 2

    显然在Test::Unit中没有assert_false。您将如何通过扩展断言并添加文件config/initializers/assertions_helper.rb来添加它?这是最好的方法吗?我不想修改test/unit/assertions.rb。顺便说一句,我不认为这是多余的。我使用的是assert_equalfalse,something_to_evaluate。这种方法的问题是很容易意外使用assertfalse,something_to_evaluate。这将始终失败,不会引发错误或警告,并且会在测试中引入错误。 最佳答案

  8. ruby - 是否有 Rack::Session::Cookie 用法的基本示例? - 2

    我找不到任何使用Rack::Session::Cookie的简单示例,并且希望能够将信息存储在cookie中,并在以后的请求中访问它并让它过期.这些是我能找到的唯一示例:HowdoIset/getsessionvarsinaRackapp?http://rack.rubyforge.org/doc/classes/Rack/Session/Cookie.html这是我得到的:useRack::Session::Cookie,:key=>'rack.session',:domain=>'foo.com',:path=>'/',:expire_after=>2592000,:secret=

  9. ruby-on-rails - 为什么在编写 Rails 测试时是 'assert_not' 而不是 '!'? - 2

    考虑这个例子,我们想检查是否允许用户使用空白名称(不应该):test"nameshouldbepresent"do@user.name=""assert_not@user.valid?end问题是为什么assert_not存在?如果我们像这样使用assert会不会更好:test"nameshouldbepresent"do@user.name=""assert!@user.valid?end 最佳答案 它可能存在用于从您的断言中删除修饰符,这可能会改变它们的结果或模糊您实际询问的内容。实际上,这主要是一种风格选择。在语言中使用unl

  10. ruby-on-rails - RSpec 中单个设置的多个断言 - 2

    我想优化一些较慢的规范。此类规范的示例如下所示:require'rspec'classHeavyComputationdefcompute_resultsleep1#somethingcomputeheavyhere"verybigstring"endenddescribeHeavyComputation,'preferredstyle,butslow'dosubject{described_class.new.compute_result}it{shouldinclude'big'}it{shouldmatch'string'}it{shouldmatch/very/}#+50oth

随机推荐