你真的会使用assert吗?
写这篇博客源于在阅读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)之间的区别;
- 一个程序错误是一个bug,永远不应该发生。
- 一个运行时错误是在程序运行的任何时候都可能会发生.
断言并不是一种处理运行时错误的机制。例如在需要输入正数的时候,用户输入了一个负数,如果用断言来检测这种情况就不是好的设计。对于这种情况需要用合适的错误检查和恢复处理的代码来进行处理。
再回到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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?