吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

防御式編程之斷言assert的使用

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

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

1、原型函數

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

void assert(int expression)

在程序運行時它會計算括號內的表達式,如果 expression為非0說明其值為真,assert()不執行任何動作,程序繼續執行后面的語句; 如果 expression為0說明其值為假,assert()將會報告錯誤,并終止程序的執行,值得了解的是,程序終止是調用abort()函數,這個函數功能就是終止程序執行,直接從調用的地方跳出,abort()函數也是標準庫函數,在

2、詳細釋義

assert() 在c標準庫中的

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

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

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

當定義了NDEBUG之后,assert()執行的具體函數就變成了 ((void)0),這表示啥也不干了,宏里面這樣用的目的是防止該宏被用作右值,因為void類型不能用作右值。 所以當在頭文件中定義了NDEBUG之后,assert()的檢測功能就自動失效了。

  • 未定義NDBUG時:

可以看到assert()執行實際上是通過三目運算符來判斷表達式e的真假,執行相應的處理。 當表達式e為真時,執行(void)0,即什么也不執行,程序繼續運行; 當表達式e為假時,那么它會打印出來assert的內容、當前的文件名、當前行號,接著終止程序執行。

3、用法舉例

在未定義NDBUG時,assert()功能生效的情況下,來看一個簡單的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)來判斷; 當 i > 0 時,assert的判斷表達式為真,assert不生效; 當 i < 0 時,assert的判斷表達式為假,assert生效。

在程序第5行 i = 8,執行完assert后,程序將執行后續的printf打印出 i 的值; 而在第8行 i = -8,執行完assert后,程序將終止,不會執行后續的printf。

4、使用注意事項

使用assert的核心原則是:用于處理絕不應該發生的情況,這就是為什么應該在程序Debug版本中使用,這是為了將主觀上不應該發生的錯誤在Debug版本中就應該解決掉,從而在程序Release版本時不會產生這種不應該發生的類型的錯誤。

  • 和if的區別

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

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

if是一個關鍵字,一般用于根據條件來判斷邏輯的正確性,即是否根據條件對應執行,Debug和Release版本中都可以使用,例如下面用if的時候,就允許這些判斷條件是正常發生的,是合理的,需要根據發生的條件執行對應的邏輯,程序可以往下執行。

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

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

#include 
#include 
void fun(int a, int b)
{
    if(0 == b)
        return;
    int i = a / b;
}
  • 用于判斷函數的入參

一般assert可以用于判斷函數入參的合法性,比如入參值是否符合,指針是否為空:

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

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

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

一般一個assert只用一個判斷語句來實現,如果在一個assert中使用多條判斷語句,當錯誤發生時,會不知道是哪個條件語句出現錯誤,錯誤表現的就不直觀。

#include 
#include 
void fun1(int a, int b) //錯誤使用
{
    assert(a > 0 && b > 5);
    ...
}
void fun2(int a, int b) //正確使用
{
    assert(a > 0);
    assert(b > 5);
    ...
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 編程
    +關注

    關注

    88

    文章

    3637

    瀏覽量

    93986
  • 函數
    +關注

    關注

    3

    文章

    4346

    瀏覽量

    62977
  • 編譯器
    +關注

    關注

    1

    文章

    1642

    瀏覽量

    49287
  • void
    +關注

    關注

    0

    文章

    23

    瀏覽量

    9901
  • ASSERT
    +關注

    關注

    0

    文章

    17

    瀏覽量

    7278
收藏 人收藏

    評論

    相關推薦

    C語言中assert的使用

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

    解析C語言斷言函數的使用

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

    何為斷言斷言的作用有哪些?斷言的種類 斷言層次結構

    斷言主要用來檢查仿真過程中存在的時序問題,如果存在異常情況,斷言會報警。一般在數字電路設計中都要加入斷言斷言占整個設計的比例應不少于30%。
    的頭像 發表于 08-28 11:16 ?8550次閱讀
    何為<b class='flag-5'>斷言</b>?<b class='flag-5'>斷言</b>的作用有哪些?<b class='flag-5'>斷言</b>的種類 <b class='flag-5'>斷言</b>層次結構

    C語言assert(斷言)簡介

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

    如何在if和assert中做選擇

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

    請問HAL函數對Handle有效性的檢查為什么不是用assert_param斷言

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

    斷言ASSERT)的用法

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

    如何在XC8中使用斷言的?

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

    嵌入開發中防御編程的要求

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

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

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

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

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

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

    為什么項目中的代碼需要有Assert斷言語句?
    的頭像 發表于 03-03 14:12 ?2803次閱讀

    STM32函數庫Assert斷言機制

    編寫代碼時,我們總是會做出一些假設,斷言就是用于在代碼中捕捉這些假設,可以將斷言看作是異常處理的一種高級形式。斷言表示為一些布爾表達式,程序員相信在程序中的某個特定點該表達式值為真。可以在任
    發表于 02-08 15:29 ?2次下載
    STM32函數庫<b class='flag-5'>Assert</b><b class='flag-5'>斷言</b>機制

    RT-Thread 大會:utest提供的斷言方法

    utest提供的斷言方法:Utest單元測試框架提供了-系列的assert 宏,用于測試用例判斷運行結果。
    的頭像 發表于 05-27 16:23 ?1283次閱讀
    RT-Thread 大會:utest提供的<b class='flag-5'>斷言</b>方法

    C語言斷言函數assert()的應用,清晰明了!

    這樣可以快速發現并定位軟件問題,同時對系統錯誤進行自動報警。對于在系統中隱藏很深,用其他手段極難發現的問題也可以通過斷言進行定位,從而縮短軟件問題定位時間,提高系統的可測性。
    的頭像 發表于 04-12 10:02 ?1169次閱讀
    百家乐官网软件辅助| 百家乐视频游戏帐号| 新皇冠现金网怎么样| 足球百家乐官网系统| 大发| 三亚百家乐官网的玩法技巧和规则| 全讯网qx1860.com| 五张百家乐官网的玩法技巧和规则 | 财神娱乐城打不开| 澳门百家乐官网论| 盖州市| 二八杠算法| 百家乐视频裸聊| 百家乐官网稳中一注法| 威尼斯人娱乐城会员开户| 百家乐官网图形的秘密破解| 二八杠 | 威尼斯人娱乐会所| 在线百家乐官网策略| 海立方百家乐官网赢钱| 桐城太阳城招聘| 棋牌百家乐程序破解| 百家乐官网赌场策略大全| 合乐娱乐| 模拟百家乐下| 百家乐最长的缆| 百家乐官网筹码真伪| 百家乐官网投注法则| 娱乐城开户送金| 四方百家乐的玩法技巧和规则 | 大发888下载 大发888游戏平台| 百家乐公式计算| 竞彩足球推荐| 大发888娱乐网下 | 百家乐官网翻天腾讯视频| 娱乐城开户送体验金| 大发888下载网站| 万人迷百家乐的玩法技巧和规则| 百家乐书| 百家乐投注法减注| 百家乐破解视频|