- 一、前言
- 二、assert 断言
- 三、if VS assert
- 四、总结
一、前言
当我们滚动代码时,我们经常需要检查代码的安全性,例如:
1. 指针是空的吗?
2. 除数是否为 0
3. 函数调用的返回结果是否有效?
4. 打开文件成功吗?
检查这种边界条件的手段一般是 if 或者 assert 断言,无论使用哪一种,都可以达到检查的目的。那么这是否意味着两者可以随意使用,想到哪一个就用哪一个呢?
我们来谈谈这篇短文:在不同的场景下,应该用 if,还是要用 assert 断言?
当我写这篇文章时,我想起了孔乙己先生的问题:茴香豆“茴”有有多少种写法?
我们似乎没有必要担心如何选择,因为我们都可以实现我们想要的功能。我以前也这么认为,但现在我不这么认为了。
成为技术大牛,获得更好offer,也许就在这些细节之间,胜负就分开了。
二、assert 断言
刚才,我问了一位嵌入式开发者,他在附近工作了5 多年:if 和 assert 如何选择?assert 是干什么的?
看来有必要简单说一下 assert 断言。
assert() 原型为:
1. 如果宏的参数值为非零值,则不进行任何操作(no action);
2. 如果宏的参数为零,打印诊断信息并呼叫abort()。
例如,以下代码:
1. 当 b 不是 0 ,assert 断言什么都不做,程序向下执行;
2. 当 b 0 ,assert 断言打印错误信息,终止程序;
在功能方面,assert(0 != b); 等价于以下代码:
assert 是宏,不是函数
在 assert.h 头文件中有以下定义:
既然是宏定义,说明宏替换是在预处理时进行的。
从以上定义可以看出:
三、if VS assert
用代码片段来描述问题更容易理解。
如果开发人员写上面的代码,肯定会被领导面试!存在以下问题:
1. 使用 if 检查句子
2. 使用 assert 检查断言
3. 你喜欢哪一个?
首先,上述 2 种检验 *** 在实际代码中非常常见,在功能上似乎没有影响。因此,没有严格的错误和正确的区别,其中许多取决于每个人不同的偏好和习惯。
(1) assert 支持者
我作为 my_concat() 函数的实现者的目的是拼接字符串,所以输入的参数必须合法有效,调用者需要对此负责。如果输入的参数无效,我会非常惊讶!我该怎么办:崩溃给你看!
(2)if 支持者
我写的 my_concat() 函数很强,所以我预计调用器会乱搞,故意引入一些无效参数来测试我的编码水平。没事,来吧,我可以处理任何事情!
这两个派别的理由似乎都很充分!到底该怎么选择?真的跟着感觉走吗?
假设我们严格按照常规流程开发一个项目:
1. 在开发阶段,编译选项中不定义 NDEBUG 这个宏,那么 assert 发挥作用;
2. 项目发布时,在编译选项中定义了 NDEBUG另一个宏,那么 assert 相当于空语句;
也就是说,只有 debug 开发阶段,用 assert 断言可以正确检查参数无效。release 阶段,assert 不起作用。如果调用器传递无效参数,程序只会崩溃。
这是什么意思?代码中存在 bug?还是代码不够强壮?
从我个人的理解来看,这是单元测试写得不好,参数无效的 case!
4. assert 的本质
assert 是为了验证有效性。它更大的作用是让我们的程序在开发阶段尽可能 crash。每一次的 crash,代码中存在 bug,我们需要纠正它。
写一个 assert 断言时,说明断言失败是不允许的,也是不允许的。功,程序才能继续执行。
5. if-else 的本质
if-else 语句用于逻辑处理,用于处理各种可能的情况。也就是说,每个分支都是合理的,是允许的,我们必须处理这些分支。
6. 我喜欢的版本
对于参数:我认为输入的参数必须有效。如果有无效参数,则代码中存在 bug,这种情况不允许发生,必须解决。
资源分配结果(malloc 函数):我认为资源分配失败是合理的,是可能的,是允许的,我也处理过这种情况。
当然,这并不意味着要使用 进行参数检查assert,主要根据不同的场景和语义来判断。例如,以下示例:
flag 参数代表不同的分支,给 赋值g_state 使用后,必须保证赋值结果的正确性assert 断言。
四、总结
本文分析了 C 语言中晦涩模糊的概念似乎有有点虚幻,但我们确实需要停下来仔细考虑。
如果有些场景真的处理不好,我会问自己一个问题:
这种情况允许吗?
不允许:用 assert 断言,在开发阶段尽量发现所有错误;
允许:用 if-else,说明这是一个需要下一步处理的合理逻辑。
本文转载自微信公众号「IOT物联网小镇」,请联系以下二维码。IOT物联网小镇微信官方账号。