在學(xué)習C語言的時候,相信很多小伙伴都會看過斷言這一章,但是從事嵌入式軟件開發(fā)的領(lǐng)域,我們卻很少用到斷言,在沒有接觸RTOS之前,我甚至不曉得斷言原來有如此大的作用。
關(guān)于斷言的作用:確保軟件的正常運行,一旦出現(xiàn)異常進行及時止損的一種機制,斷言是在軟件運行階段的一種保護機制,并不存在于預(yù)處理和編譯階段。
在RTOS中斷言的應(yīng)用其實很簡單:
RT_ASSERT(spi_dev_name); //斷言spi_dev_name存不存在
具體的實現(xiàn)如下在:
#define RT_ASSERT(EX) \
if (!(EX)) \
{ \
rt_assert_handler(#EX, __FUNCTION__, __LINE__); \
}
ASSERT 是通過宏定義實現(xiàn)的,判斷EX是否存在,如果不存在就執(zhí)行rt_assert_handler函數(shù);有個小知識點補充下,就是\的作用,如果沒有他,那么#define的宏定義只有當前行算數(shù),有了它那么就是下面的內(nèi)容也包括在宏定義中,\可以理解為連接符。
執(zhí)行的rt_assert_handler中有兩個參數(shù)比較特殊:__FUNCTION__和__LINE__這兩個是編譯器相關(guān)的參數(shù):
__FUNCTION__:用于定位當前執(zhí)行的函數(shù):也就是函數(shù)名。
__LINE__:用于包含當前的行號,當前文件的行號。
rt_assert_handler函數(shù)的實現(xiàn)如下:
/**
* 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);
}
}
這個函數(shù)看著很復(fù)雜,其實分析起來,你會發(fā)現(xiàn)功能很簡單,首先RT_USING_MODULE宏并沒有定義,所以這塊可以直接忽略,假定rt_assert_hook = RT_NULL,那么實際執(zhí)行的函數(shù)就只有:
rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex_string, func, line);
while (dummy == 0);
打印斷言錯誤信息,包括錯誤內(nèi)容,觸發(fā)函數(shù),所在行號等信息。
然后進入while死循環(huán),阻塞當前函數(shù)執(zhí)行。
阻塞的目的是為了將當前線程的異常影響降到最低,這并不能保證整個軟件的功能正常,但是他能保證系統(tǒng)運行正常,方便我們定位錯誤以及調(diào)試異常。