assert(断言)是C语言标准库中提供的一种用于调试节俭原防御式编程机制。它主要用于验证程序中的假设条件是否成立,帮助开发者尽早发现逻辑错误,非法参数或异常状态等。
assert宏定义
assert()函数实际上是一个宏定义,并不是我们常见的API函数。如果使用的话,必须添加头文件#include <assert.h>。
assert工作原理
assert(表达式);
assert()传入的是”表达式“,而非常见的数值。这也是符合前面所说的assert为宏定义的设定。
assert()会计算表达式的值,依结果进入不同的分支处理。
当表达式为真:程序继续正常执行,assert 不产生任何副作用。
如果值为假 :assert 会向标准错误流(stderr)打印一条诊断信息(包含表达式文本、源文件名、行号),然后调用 abort() 函数立即终止程序执行。
当我们的代码运行过程中,如果有stderr打印,并”吐出来"表达式,文件名和行号,然后退出了。这也就意味着,打印所示的assert没有通过。这样我们就一定会停下来分析bug了。
assert基本用法
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
void process(uint32_t *ptr)
{
assert(ptr != NULL);
int i;
for(i = 0; i < 8; i++)
{
ptr[i] = i;
}
}
int main(int argc, char const *argv[])
{
uint32_t *dst;
dst = malloc(-1);
printf("dst = %p\r\n", dst);
process(dst);
return 0;
}如果第8行表达式ptr != NULL为真,则还做罢了;但如果为假,则程序会停留 在第8行,并打印出来对应的文件名与行数。如下图所示:

assert在STM32
上面为通用的作法,如果换成我们的STM32实现又如何呢?
我估计是考虑到引入clib库的问题,ST官方并没有使用C库的assert.h文件,而是自已写了一套文件名为stm32_assert.h,并将断言失败的输出方式,输出内容交由用户自行处理。故stm32提供了assert_param的宏定义,并提供了assert_failed()的API回调函数,是不是很贴心!
#ifdef USE_FULL_ASSERT /** * @brief The assert_param macro is used for function's parameters check. * @param expr If expr is false, it calls assert_failed function * which reports the name of the source file and the source * line number of the call that failed. * If expr is true, it returns no value. * @retval None */ #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) /* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t *file, uint32_t line); #else #define assert_param(expr) ((void)0U) #endif /* USE_FULL_ASSERT */
我们在STM32项目开发过程中,要先定义USE_FULL_ASSERT,以打开assert断言功能,接着我们再实现assert_failed()回调函数。
在调试阶段,有jlink调试器挂接时,可以在assert_failed()函数中只添加while(1),单纯的让程序停在这里,方便调试查看。而在测试阶段,则需要在assert_failed()函数中实现上述文件名和行号的日志输出了。
总结
assert断言是软件开发阶段非常重要的、高效的一种调试手段。大家一定要利用起来!
欢迎大家关注我,我是你们的老朋友jobs。
我要赚赏金
