程序小白
认证:优质创作者
所在专题目录 查看专题
闲话内核——一切皆为程序片服务
可抢占式内核带来的挑战——并发
裸奔、事件驱动、传统多任务到底孰优孰劣?
RTOS中的断言机制——assert
作者动态 更多
小小调度器——开局default,优雅总藏于细节之中
3星期前
小小调度器——调度器核心的纯C实现
04-01 14:09
小小调度器——原来C代码还能这么写,原作者没少挨打吧!
03-27 15:42
解析由系统库引发的hardfault血案(RT-Thread+ESP32)
2023-07-17 16:04
TINA瞬时现象仿真分析——运放缓冲器振铃
2023-02-28 11:38

RTOS中的断言机制——assert

      在学习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死循环,阻塞当前函数执行。

阻塞的目的是为了将当前线程的异常影响降到最低,这并不能保证整个软件的功能正常,但是他能保证系统运行正常,方便我们定位错误以及调试异常。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 2
收藏 2
关注 115
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧