你真的会使用assert吗?

摘要:
我写这个博客是因为在阅读lighttpd源代码时遇到了一个关于assert应用程序的问题。在读取lighttpd源代码时,发现对malloc调用结果进行了许多断言检查,例如Buffer c:fuffer*Buffer_init{Buffer*b;b=malloc;assert;b-˃ptr=NULL;b-˃size=0;b-˃used=0;returnb;}这里的断言似乎有问题。当实际发布版本运行时,malloc是否返回NULL?返回lighttpd以断言malloc函数的返回值。我认为这属于这个问题。这应该是运行时错误,而不是程序错误;因此,我认为C和指针中malloc返回的NULL是通过错误检查分配器处理的。

写这篇博客源于在阅读lighttpd源代码是遇到的一个关于assert应用的疑问。

在阅读lighttpd源代码时,发现比比皆是的对malloc的调用结果进行assert检查,比如:Buffer.c:

复制代码
buffer* buffer_init(void) {
buffer *b;

b = malloc(sizeof(*b));
assert(b);

b->ptr = NULL;
b->size = 0;
b->used = 0;

return b;
}
复制代码

这里的assert(b)似乎有问题,实际release版本在运行中难道不会发生malloc返回NULL的情况吗?之后在阅读《Writing Solid Code 》一书时找到了答案。

对assert的基本用法就不再累述了,下面总结一下assert的实际应用的Recommended practice吧:

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

主要有以下情况:

  • 指针不是NULL的断言;
  • index值或size值不是负值或小于已知限值的断言;这一条也可以这么描述:要从程序中删去无定义的特性或者在程序中使用断言来检查出无定义特性的非法使用

2、每个断言必须在头文件中的函数功能描述的断言部分进行说明(不要浪费别人的时间 ─── 详细说明不清楚的断言 ),例如:

*  Asserts:
* 'size' is no greater then LIMIT.
* 'format' is not NULL.
* The function result is no greater than LIMIT.
*/

如果没有断言, 写 “Nothing”:

 *  Asserts:
* Nothing
*/
(以上的格式也许严格了一些,不过如果真的这么做,对代码的可阅读性会很有帮助)

3、断言和错误校验的区别

正确使用断言,必须要清楚程序错误(program errors)和运行时错误(run- time errors)之间的区别; 

  1. 一个程序错误是一个bug,永远不应该发生。
  2. 一个运行时错误是在程序运行的任何时候都可能会发生.

断言并不是一种处理运行时错误的机制。例如在需要输入正数的时候,用户输入了一个负数,如果用断言来检测这种情况就不是好的设计。对于这种情况需要用合适的错误检查和恢复处理的代码来进行处理。

再回到lighttpd中对malloc函数的返回值进行assert断言,我觉得也属于这个问题,这应该是一个运行时错误,而不是程序错误;所以,我觉得《C和指针》一书中对malloc返回NULL处理是通过一个错误检查分配器来处理的。

4、断言和bug

断言大致分为前置条件(Preconditions)、后置条件(Postconditions)、不变性条件(Invariants)

如果前置条件不成立,发生Assertion violations,则调用该函数的代码存在bug,需要尽快找到并解决;

如果后置条件不成立,发生Assertion violations,则(函数的)实现代码存在bug,需要尽快找到并解决;

例如:

复制代码
void doBlah(int x)

{

assert(x!=0);

....

}
复制代码

这段代码说明这个函数的调用不可能传入参数0,如果发生这种情况,说明调用这个函数的代码存在bug;

以上是自己的一点理解,欢迎高手指正!!!
参考:How to use assertions in C

        《Writing Solid Code 

免责声明:文章转载自《你真的会使用assert吗?》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇令牌桶(Token Bucket)ORACLE--SQL日常问题和技巧1(列变行、自定义查询结构、将字符串分割为多条记录)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

.netcore持续集成测试篇之开篇简介及Xunit基本使用

系列目录 为了支持跨平台,微软为.net平台提供了.net core test sdk,这样第三方测试框架诸如Nunit,Xunit等只需要按照sdk提供的api规范进行开发便可以被dotnet cli工具调用,这样就解决了在持续集成过程中第三方框架依赖于windows平台上的各自runner的问题,使得测试框架开发者不需要花费很大功夫就可以快速迁移到.n...

敏捷软件开发——第5章 重构

第5章 重构   在Martin Fowler的名著《重构》一书中,他把重构定义为:“在不改变代码外在行为的前提下对对代码做出修改,以改进代码内部结构的过程。”可是我们为什么要改进已经能够工作的代码结构呢?我们不是都知道“如果它没有坏,就不要去修理它!”吗?   每一个软件模块都有3项职责。第一个职责是它运行起来所完成的功能。这也是该模块得以存在的原因。第...

C#中的release和debug模式

以下内容来源:https://www.cnblogs.com/rgjycs/p/9254332.html 在程序调试时的debug和release 网上有如下的描述:Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好...

assert()函数用法总结

assert()函数用法总结assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义: #include <assert.h>void assert( int expression );   assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向s...

pytest框架(一)

代码示例一 1 #coding=utf-8 2 3 deffunc(x): 4 return x + 1 5 6 7 deftest_answer(): 8 assert func(3) == 5 运行结果 E:pyYouYoupytest_demo>pytest test_sample.py ================...

TypeError: Identifier 'assert' has already been declared

1、错误描述 > const assert=require('assert'); TypeError: Identifier 'assert' has already been declared at repl:1:1 at REPLServer.defaultEval (repl.js:262:27) at bound (...