在学习C语言的时候,相信很多小伙伴都会看过断言这一章,但是从事嵌入式软件开发的领域,我们却很少用到断言,在没有接触RTOS之前,我甚至不晓得断言原来有如此大的作用。
关于断言的作用:确保软件的正常运行,一旦出现异常进行及时止损的一种机制,断言是在软件运行阶段的一种保护机制,并不存在于预处理和编译阶段。
在RTOS中断言的应用其实很简单:
RT_ASSERT(spi_dev_name); //断言spi_dev_name存不存在
具体的实现如下在:
#define RT_ASSERT(EX) \
if (!(EX)) \
{ \
rt_assert_handler(#EX, __FUNCTION__, __LINE__); \
}
ASSERT 是通过宏定义实现的,判断EX是否存在,如果不存在就执行rt_assert_handler函数;有个小知识点补充下,就是\的作用,如果没有他,那么#define的宏定义只有当前行算数,有了它那么就是下面的内容也包括在宏定义中,\可以理解为连接符。
执行的rt_assert_handler中有两个参数比较特殊:__FUNCTION__和__LINE__这两个是编译器相关的参数:
__FUNCTION__:用于定位当前执行的函数:也就是函数名。
__LINE__:用于包含当前的行号,当前文件的行号。
rt_assert_handler函数的实现如下:
/**
* The RT_ASSERT function.
*
* @param ex the assertion condition string
* @param func the function name when assertion.
* @param line the file line number when assertion.
*/
void rt_assert_handler(const char *ex_string, const char *func, rt_size_t line)
{
volatile char dummy = 0;
if (rt_assert_hook == RT_NULL)
{
#ifdef RT_USING_MODULE
if (dlmodule_self())
{
/* close assertion module */
dlmodule_exit(-1);
}
else
#endif
{
rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex_string, func, line);
while (dummy == 0);
}
}
else
{
rt_assert_hook(ex_string, func, line);
}
}
这个函数看着很复杂,其实分析起来,你会发现功能很简单,首先RT_USING_MODULE宏并没有定义,所以这块可以直接忽略,假定rt_assert_hook = RT_NULL,那么实际执行的函数就只有:
rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex_string, func, line);
while (dummy == 0);
打印断言错误信息,包括错误内容,触发函数,所在行号等信息。
然后进入while死循环,阻塞当前函数执行。
阻塞的目的是为了将当前线程的异常影响降到最低,这并不能保证整个软件的功能正常,但是他能保证系统运行正常,方便我们定位错误以及调试异常。