0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

防御式編程之?dāng)嘌詀ssert的使用

CHANBAEK ? 來源:明解嵌入式 ? 作者:Sharemaker001 ? 2023-04-19 11:35 ? 次閱讀

防御式編程的重點(diǎn)就是需要防御一些程序未曾預(yù)料的錯(cuò)誤,這是一種提高軟件質(zhì)量的輔助性方法,斷言assert就用于防御式編程,編寫代碼時(shí),我們總是會(huì)做出一些假設(shè),斷言就是用于在代碼中捕捉這些假設(shè)。 使用斷言是為了驗(yàn)證預(yù)期的結(jié)果——當(dāng)程序執(zhí)行到斷言的位置時(shí),對(duì)應(yīng)的斷言應(yīng)該為真; 若斷言不為真時(shí),程序會(huì)終止執(zhí)行,并給出錯(cuò)誤信息。 可以在任何時(shí)候啟用和禁用斷言驗(yàn)證,因此可以在程序調(diào)試時(shí)啟用斷言而在程序發(fā)布時(shí)禁用斷言。 同樣,程序投入運(yùn)行后,最終用戶在遇到問題時(shí)可以重新啟用斷言。

1、原型函數(shù)

在大部分編譯器下,assert() 是一個(gè)宏; 在少數(shù)的編譯器下,assert() 就是一個(gè)函數(shù)。 我們不需要關(guān)心這些差異,可以只把 assert()當(dāng)作函數(shù)使用即可。 即:

void assert(int expression)

在程序運(yùn)行時(shí)它會(huì)計(jì)算括號(hào)內(nèi)的表達(dá)式,如果 expression為非0說明其值為真,assert()不執(zhí)行任何動(dòng)作,程序繼續(xù)執(zhí)行后面的語句; 如果 expression為0說明其值為假,assert()將會(huì)報(bào)告錯(cuò)誤,并終止程序的執(zhí)行,值得了解的是,程序終止是調(diào)用abort()函數(shù),這個(gè)函數(shù)功能就是終止程序執(zhí)行,直接從調(diào)用的地方跳出,abort()函數(shù)也是標(biāo)準(zhǔn)庫函數(shù),在

2、詳細(xì)釋義

assert() 在c標(biāo)準(zhǔn)庫中的

#ifdef NDEBUG
#define assert(e) ((void)0)
#else
#define assert(e)  
    ((void) ((e) ? ((void)0) : __assert (#e, __FILE__, __LINE__)))
#endif

可以看到在定義了NDEBUG時(shí),assert()無效,只有在未定義NDEBUG時(shí),assert()才實(shí)現(xiàn)具體的函數(shù)功能。 NDEBUG是“No Debug”的意思,也即“非調(diào)試”。 程序一般分為Debug版本和Release版本,Debug版本是程序員在測(cè)試代碼期間使用的編譯版本,Release版本是將程序提供給用戶時(shí)使用的發(fā)布版本,一般來說斷言assert()是僅在Debug版本起作用的宏。 在發(fā)布版本時(shí),我們不應(yīng)該再依賴assert()宏,因?yàn)槌绦蛞坏┏鲥e(cuò),assert()會(huì)拋出一段用戶看不懂的提示信息,并毫無預(yù)警地終止程序執(zhí)行,這樣會(huì)嚴(yán)重影響軟件的用戶體驗(yàn),所以在發(fā)布模式下應(yīng)該讓assert()失效,另外在程序中頻繁的調(diào)用assert()會(huì)影響程序的性能,增加額外的開銷。 因此可以在

#define NDEBUG  //定義NDEBUG  
#ifdef NDEBUG
#define assert(e) ((void)0)
#else
#define assert(e)  
    ((void) ((e) ? ((void)0) : __assert (#e, __FILE__, __LINE__)))
#endif
  • 定義NDBUG時(shí):

當(dāng)定義了NDEBUG之后,assert()執(zhí)行的具體函數(shù)就變成了 ((void)0),這表示啥也不干了,宏里面這樣用的目的是防止該宏被用作右值,因?yàn)関oid類型不能用作右值。 所以當(dāng)在頭文件中定義了NDEBUG之后,assert()的檢測(cè)功能就自動(dòng)失效了。

  • 未定義NDBUG時(shí):

可以看到assert()執(zhí)行實(shí)際上是通過三目運(yùn)算符來判斷表達(dá)式e的真假,執(zhí)行相應(yīng)的處理。 當(dāng)表達(dá)式e為真時(shí),執(zhí)行(void)0,即什么也不執(zhí)行,程序繼續(xù)運(yùn)行; 當(dāng)表達(dá)式e為假時(shí),那么它會(huì)打印出來assert的內(nèi)容、當(dāng)前的文件名、當(dāng)前行號(hào),接著終止程序執(zhí)行。

3、用法舉例

在未定義NDBUG時(shí),assert()功能生效的情況下,來看一個(gè)簡(jiǎn)單的assert()使用的例子:

#include 
#include 
void main()
{
    int i = 8;
    assert(i > 0);
    printf("i = %d\\n", i);
    i = -8;
    assert(i > 0);
    printf("i = %d\\n", i);
}

可以看出在程序中使用assert(i > 0)來判斷; 當(dāng) i > 0 時(shí),assert的判斷表達(dá)式為真,assert不生效; 當(dāng) i < 0 時(shí),assert的判斷表達(dá)式為假,assert生效。

在程序第5行 i = 8,執(zhí)行完assert后,程序?qū)?zhí)行后續(xù)的printf打印出 i 的值; 而在第8行 i = -8,執(zhí)行完assert后,程序?qū)⒔K止,不會(huì)執(zhí)行后續(xù)的printf。

4、使用注意事項(xiàng)

使用assert的核心原則是:用于處理絕不應(yīng)該發(fā)生的情況,這就是為什么應(yīng)該在程序Debug版本中使用,這是為了將主觀上不應(yīng)該發(fā)生的錯(cuò)誤在Debug版本中就應(yīng)該解決掉,從而在程序Release版本時(shí)不會(huì)產(chǎn)生這種不應(yīng)該發(fā)生的類型的錯(cuò)誤。

  • 和if的區(qū)別

assert用函數(shù)來判斷是否滿足表達(dá)式條件后終止程序,在Debug版本中用assert來判斷程序的合法性,定位不允許發(fā)生的錯(cuò)誤,那么什么是不應(yīng)該發(fā)生的錯(cuò)誤,例如像下面這種除0操作,主觀上就不應(yīng)該發(fā)生,就是就要在Debug版本中檢查排除掉這種錯(cuò)誤,以免影響后續(xù)程序的執(zhí)行。

#include 
#include 
void fun(int a, int b)
{
    assert(b != 0);
    int i = a / b;
}

if是一個(gè)關(guān)鍵字,一般用于根據(jù)條件來判斷邏輯的正確性,即是否根據(jù)條件對(duì)應(yīng)執(zhí)行,Debug和Release版本中都可以使用,例如下面用if的時(shí)候,就允許這些判斷條件是正常發(fā)生的,是合理的,需要根據(jù)發(fā)生的條件執(zhí)行對(duì)應(yīng)的邏輯,程序可以往下執(zhí)行。

#include 
#include 
void fun(int a, int b)
{
   if(a > 0)
       ...
   else if(a < 0)
       ...
   else
       ...
}

因此在使用前,可以先判斷下,如果邏輯不允許發(fā)生,那么就使用assert在Debug階段將問題解決掉; 如果邏輯允許的,那么就使用if,當(dāng)然也可以用if判斷后進(jìn)行條件的return操作,來杜絕不允許邏輯,本質(zhì)是防止錯(cuò)誤的邏輯影響后續(xù)程序的執(zhí)行。 例如上述的用來判斷除0操作的例子也可以用if:

#include 
#include 
void fun(int a, int b)
{
    if(0 == b)
        return;
    int i = a / b;
}
  • 用于判斷函數(shù)的入?yún)?/strong>

一般assert可以用于判斷函數(shù)入?yún)⒌暮戏ㄐ?,比如入?yún)⒅凳欠穹?,指針是否為空?/p>

#include 
#include 
void fun1(int a)
{
    assert(a > 0);
    ...
}
void fun2(int *p)
{
    assert(p != NULL);
    ...
}
  • 不要使用影響正常邏輯的判斷條件語句

assert的判斷條件語句一定是確定的,在Debug版本中使用的排除掉錯(cuò)誤的條件邏輯,不要影響到Release版本時(shí)的正常邏輯。 例如下面的例子,在Debug版本時(shí),i++到>=100時(shí),assert生效,程序終止; 但是到了Release版本,由于要增加NDEBUG宏,assert()無效。 assert(i++ < 100)就變成了空操作(void)0;由于沒有i++語句執(zhí)行,那么while成了死循環(huán)。

#include 
#include 
void main()
{
    int i = 0;
    while(i <= 110)
    {
        assert(i++ < 100);
        printf("i = %d\\n",i);
    }
}
  • 不要用多個(gè)判斷條件語句

一般一個(gè)assert只用一個(gè)判斷語句來實(shí)現(xiàn),如果在一個(gè)assert中使用多條判斷語句,當(dāng)錯(cuò)誤發(fā)生時(shí),會(huì)不知道是哪個(gè)條件語句出現(xiàn)錯(cuò)誤,錯(cuò)誤表現(xiàn)的就不直觀。

#include 
#include 
void fun1(int a, int b) //錯(cuò)誤使用
{
    assert(a > 0 && b > 5);
    ...
}
void fun2(int a, int b) //正確使用
{
    assert(a > 0);
    assert(b > 5);
    ...
}
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3616

    瀏覽量

    93738
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4331

    瀏覽量

    62622
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1634

    瀏覽量

    49133
  • void
    +關(guān)注

    關(guān)注

    0

    文章

    23

    瀏覽量

    9874
  • ASSERT
    +關(guān)注

    關(guān)注

    0

    文章

    17

    瀏覽量

    7246
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    C語言中assert的使用

    assert意思是斷言,常用在程序的DEBUG版本中。
    發(fā)表于 07-21 14:51 ?849次閱讀

    解析C語言斷言函數(shù)的使用

    對(duì)于斷言,相信大家都不陌生,大多數(shù)編程語言也都有斷言這一特性。簡(jiǎn)單地講,斷言就是對(duì)某種假設(shè)條件進(jìn)行檢查。 在 C 語言中,斷言被定義為宏的形
    發(fā)表于 08-08 09:51 ?481次閱讀
    解析C語言<b class='flag-5'>斷言</b>函數(shù)的使用

    何為斷言?斷言的作用有哪些?斷言的種類 斷言層次結(jié)構(gòu)

    斷言主要用來檢查仿真過程中存在的時(shí)序問題,如果存在異常情況,斷言會(huì)報(bào)警。一般在數(shù)字電路設(shè)計(jì)中都要加入斷言,斷言占整個(gè)設(shè)計(jì)的比例應(yīng)不少于30%。
    的頭像 發(fā)表于 08-28 11:16 ?8441次閱讀
    何為<b class='flag-5'>斷言</b>?<b class='flag-5'>斷言</b>的作用有哪些?<b class='flag-5'>斷言</b>的種類 <b class='flag-5'>斷言</b>層次結(jié)構(gòu)

    C語言assert(斷言)簡(jiǎn)介

    assert的功能,條件為真,程序繼續(xù)執(zhí)行;如果斷言為假(false),則程序終止。
    的頭像 發(fā)表于 11-17 16:33 ?1165次閱讀
    C語言<b class='flag-5'>assert</b>(<b class='flag-5'>斷言</b>)簡(jiǎn)介

    如何在if和assert中做選擇

    的功能。以前我也是這么想的,但是,現(xiàn)在我不這么認(rèn)為。 二、assert 斷言剛才,我問了下旁邊的一位工作 5 年多的嵌入開發(fā)者:if 和 assert 如何選擇?他說:
    發(fā)表于 04-08 06:13

    請(qǐng)問HAL函數(shù)對(duì)Handle有效性的檢查為什么不是用assert_param斷言?

    )); ...... } 以HAL_SPI_Init為例,hspi參數(shù)的檢查并沒有使用assert_param斷言宏,如果是我實(shí)現(xiàn)的話,我會(huì)用assert_param(hspi != NULL)實(shí)現(xiàn)。一般
    發(fā)表于 05-08 07:00

    斷言ASSERT)的用法

    的了解,assert()的用法像是一種“契約編程”,在我的理解中,其表達(dá)的意思就是,程序在我的假設(shè)條件下,能夠正常良好的運(yùn)作,其實(shí)就相當(dāng)于一個(gè)if語句:if(假設(shè)成立){程序正常運(yùn)行;}else
    發(fā)表于 08-23 09:33

    如何在XC8中使用斷言的?

    大家好,我正在嘗試使用XC8中的斷言,但是當(dāng)我使用“*”時(shí),“斷言h”空格main(空隙){BOOL X=0;斷言(x= 1);而(1){}}我的程序停止,并且在控制臺(tái)中不顯示任何MsAGAGEM
    發(fā)表于 03-26 10:58

    嵌入開發(fā)中防御編程的要求

    嵌入產(chǎn)品的可靠性自然與硬件密不可分,但在硬件確定、并且沒有第三方測(cè)試的前提下,使用防御編程思想寫出的代碼,往往具有更高的穩(wěn)定性。防御編程
    發(fā)表于 12-15 07:20

    ARM嵌入編程之STM32的命名方法

    ARM嵌入編程之STM32的命名方法:ARM嵌入編程之STM32的命名方法
    發(fā)表于 12-22 06:29

    何為斷言?斷言該怎么使用呢

    存在錯(cuò)誤。因此,斷言是提高程序可靠性的有效手段。也是開發(fā)階段快速定位問題的一種很好防御編程方法。在C語言中,斷言是一些條件判斷的宏。比如C
    發(fā)表于 09-21 14:59

    怎么理解Assert中的斷言語句?

    為什么項(xiàng)目中的代碼需要有Assert斷言語句?
    的頭像 發(fā)表于 03-03 14:12 ?2749次閱讀

    STM32函數(shù)庫Assert斷言機(jī)制

    編寫代碼時(shí),我們總是會(huì)做出一些假設(shè),斷言就是用于在代碼中捕捉這些假設(shè),可以將斷言看作是異常處理的一種高級(jí)形式。斷言表示為一些布爾表達(dá)式,程序員相信在程序中的某個(gè)特定點(diǎn)該表達(dá)式值為真??梢栽谌?/div>
    發(fā)表于 02-08 15:29 ?2次下載
    STM32函數(shù)庫<b class='flag-5'>Assert</b><b class='flag-5'>斷言</b>機(jī)制

    RT-Thread 大會(huì):utest提供的斷言方法

    utest提供的斷言方法:Utest單元測(cè)試框架提供了-系列的assert 宏,用于測(cè)試用例判斷運(yùn)行結(jié)果。
    的頭像 發(fā)表于 05-27 16:23 ?1227次閱讀
    RT-Thread 大會(huì):utest提供的<b class='flag-5'>斷言</b>方法

    C語言斷言函數(shù)assert()的應(yīng)用,清晰明了!

    這樣可以快速發(fā)現(xiàn)并定位軟件問題,同時(shí)對(duì)系統(tǒng)錯(cuò)誤進(jìn)行自動(dòng)報(bào)警。對(duì)于在系統(tǒng)中隱藏很深,用其他手段極難發(fā)現(xiàn)的問題也可以通過斷言進(jìn)行定位,從而縮短軟件問題定位時(shí)間,提高系統(tǒng)的可測(cè)性。
    的頭像 發(fā)表于 04-12 10:02 ?1109次閱讀