那曲檬骨新材料有限公司

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

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

3天內不再提示

【C語言進階】利用assert高效排查你的C程序

嵌入式物聯(lián)網開發(fā) ? 來源:嵌入式物聯(lián)網開發(fā) ? 作者:嵌入式物聯(lián)網開發(fā) ? 2022-08-31 13:27 ? 次閱讀
眾所周知,我們在實際開發(fā)C程序的時候,往往是編碼容易——調試困難,修改容易——排查困難。我們在開發(fā)過程中,debug占據了我們很大一部分的時間,而正確地使用各種編碼手段,可以有效地提升排查問題代碼的效率。筆者從自己的實踐經驗出發(fā),給大家分享一個用于編碼/調試階段高效發(fā)現(xiàn)問題代碼的利器,這就是大名鼎鼎的**assert**。通過閱讀本文,你將了解到以下內容:
  • 什么是assert?
  • assert有什么用?
  • assert怎么使用?
  • assert的常規(guī)操作有哪些?

什么是assert?


? assert它的中文含義是“斷言”,它被包含在中,往往給使用者呈現(xiàn)的形式為: assert() 。因此,很多開發(fā)者認為它就是一個函數,可能它的原型就是void assert(int expression); 但研究過assert.h的,一定會發(fā)現(xiàn),其實并不是。

? assert的真身,其實是一個宏定義,只不過是一個帶參數輸入的宏定義,與我們之前一篇八卦Linux內核設計的max宏定義 (【Linux內核】從小小的宏定義窺探Linux內核的精妙設計)類似的。廬山真面目如下所示:

#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__))

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zc6EAp8U-1661923571346)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]

? 從它的定義,我們可以很清晰的知道,真正起到打印作用的是_assert,而它才是真正的一個函數。原型為:

void _assert(const char *e, const char *file, int line);

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dax1ldZf-1661923571352)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]


assert有什么用?


? 本文的主題是利用assert高效排查問題代碼,自然assert的用途就是排查代碼;但是,具體它的功能是怎么體現(xiàn)呢?假設有如下代碼,一個測試函數的實現(xiàn)片段:

int test_function(int a, int *b)
{
    assert(a > 1);  /* 斷言:入參a的值一定大于1 */
    assert(b);      /* 斷言: 入參b指針一定不是NULL */

    /* Do other things here ... */
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ejym7Jij-1661923571353)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]

? 如代碼所示,有一個測試函數test_function,接收2個入參,一個是int型的a變量,一個int *類型的b指針;在函數的開始,我們就用assert分別對a和b做了斷言,確保它們有正確的輸入。假設我們有如下的函數調用的測試代碼:

{
    int a = 7;
    int *b = &a;
    
    test_function(a, b);

    /* Do other things here ... */
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-E4QQ143R-1661923571355)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]

? 很明顯,當如上代碼調用test_fucntion時,內部的兩個assert判斷均為【真】,那么什么事情也不會發(fā)生,assert就像一個優(yōu)雅的淑女,靜靜地站在那里看著你。

? 當我們的測試代碼做如下調整:

{
    int a = 0;
    int *b = &a;
    
    test_function(a, b);

    /* Do other things here ... */
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qPbDKDBb-1661923571357)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]

? 很明顯,test_function的第一個assert語句不為【真】,那么它就像山洪一樣要爆發(fā)了,終止程序運行的同時,會輸出類似的錯誤提示: Assertion failed: a > 1,file xxx.c, line 128,這段錯誤提示,不僅告訴了我們哪個條件判斷出錯了,并且還告訴了我們出錯的位置在哪個文件的哪一行,這是多么智能啊!由此可見,它真正的威力在于【代碼出錯】時,即當代碼沒有按照我們的斷言進行時,我們就應該停下來,排查下為何會有錯誤的參數輸入,這樣我們就可以將bug在出現(xiàn)苗頭的時候就把它消滅掉。


assert怎么使用?


? 其實,上面的示例代碼已經展示了如何使用assert,但是我們需要補充的是,一般在使用assert斷言語句的時候,需要在對應的.c文件加上對assert.h的引用,否則編譯會報錯誤。

? assert這么智能的利器是非常有利于我們寫出高質量不易出錯的代碼的,通常富有經驗的程序員都會很擅長使用assert語句,把assert打在恰當的語句中,可以最大限度地提升我們的代碼質量。但是,很多開發(fā)者開始有疑惑了,要是每條語句,每個判斷都加上assert,那么就算全部assert的情況都是【真】,也夠CPU忙一會了,這樣似乎有些浪費CPU的計算能力,以追求高效的C語言編程,可容不下這樣的事情發(fā)生。那,這可怎么辦呢?

? 為避免以上情況的發(fā)生,我們作為assert的使用者,一般只需要在開發(fā)調試階段才使用assert,而在正式發(fā)布的版本是需要去掉assert的。這樣疑惑就更大了,發(fā)布版本一條條刪掉assert調用,萬一刪錯了代碼呢?設計者總是聰明的,他們也早就想到了這一點,這不他們也提供了解決方案。開頭的時候,我們介紹了assert是一個宏,但并沒有完全展示它的全貌。現(xiàn)在開始展示它的真容:

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

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-69cPczpO-1661923571359)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]

? 聰明的你,一定也發(fā)現(xiàn)了,我們只需要在.c文件#include 之前,加上一句#define NDEBUG 1就可以把相應.c中的assert(e)全部變成((void)0);而((void)0)本身是個無效調用代碼,在實際的編譯過程中是會被優(yōu)化掉的,這樣我們僅增加對NDEBUG(NO DEBUG的意思)的宏定義,就可以把全部的assert給摒棄了,是不是很智能呢?


assert的常規(guī)操作有哪些?


? 正如上面所述,assert這么智能,但是我們也不能濫用,只需要在恰當的位置作為特定的判斷;通常來說,我們有以下一些情景可以考慮使用assert語句:

  • 函數的入參判斷,對錯誤的入參及時處理
  • 對重點調用的系統(tǒng)函數的返回結果做判斷,使用assert保證系統(tǒng)調用的結果是正確的,避免外部使用不正確的系統(tǒng)調用而出現(xiàn)錯上加錯的情況;
  • switch語句中,如果不允許出現(xiàn)default的情況,可以考慮在default分支中加入assert(0);
  • 執(zhí)行計算時,做計算的輸入或計算結果的輸出等做下判斷,比如除數不能為0,比如一個百分比值不能超過100%等等。

? 綜述,assert是把雙刃劍,出錯時它能很優(yōu)秀地暴露問題代碼,非常有利于我們排查代碼,從而以最快的速度找到問題并解決問題;同時,它的頻繁調用,一定程度上加上了CPU的處理,做一些無畏的判斷,“簡直就是在浪費生命”。所以,在實際開發(fā)過程中,我們務必要嚴謹細致地使用assert,讓它更好地為我們服務。

? 只有不自負且思維嚴謹的人才能使用好assert,我們只有做到了不自負,不對自己的代碼打100%的包票,相信是代碼總會有出錯的時候,才會逐步養(yǎng)成思維嚴謹的習慣,反而對自己的代碼質量有更大的提升。

? 本文對assert的介紹和使用做了一番總結,文中難免有紕漏之處,還望讀者誠心指正,感謝。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    180

    文章

    7614

    瀏覽量

    137724
  • C程序
    +關注

    關注

    4

    文章

    255

    瀏覽量

    36139
  • ASSERT
    +關注

    關注

    0

    文章

    17

    瀏覽量

    7278
收藏 人收藏

    評論

    相關推薦

    C語言assert的使用

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

    C語言assert(斷言)簡介

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

    C語言進階

    C語言進階見附件
    發(fā)表于 08-13 15:51

    C語言進階書分享!

    挺好的。c語言進階.pdf (1.78 MB )
    發(fā)表于 10-16 02:44

    100個經典C語言程序

    c語言編寫,c語言的100個經典程序,單片機的應用,開發(fā)利用
    發(fā)表于 12-17 11:46 ?11次下載

    時鐘設計程序C語言

    時鐘設計程序。時鐘設計程序。時鐘設計程序C語言】時鐘設計程序
    發(fā)表于 12-28 12:02 ?0次下載

    單片機IO擴展(進階)程序集合【C語言+匯編】

    單片機IO擴展(進階)程序集合【C語言+匯編】
    發(fā)表于 01-06 11:03 ?8次下載

    單片機IO擴展(進階)程序集合【C語言

    單片機IO擴展(進階)程序集合【C語言】。
    發(fā)表于 01-06 11:04 ?23次下載

    DSP C2000程序員高手進階

    DSP C2000程序員高手進階 PDF 版
    發(fā)表于 05-06 15:13 ?33次下載

    DSP C2000程序員的高手進階

    DSP C2000程序員的高手進階
    發(fā)表于 10-16 13:16 ?20次下載
    DSP <b class='flag-5'>C</b>2000<b class='flag-5'>程序</b>員的高手<b class='flag-5'>進階</b>

    C語言進階學習課件資料合集

    本文檔的主要內容詳細介紹的是C語言進階學習課件資料合集包括了:第1節(jié)-數據的存儲,第2節(jié)-指針的進階,第3節(jié)-字符串+內存函數的介紹,第4節(jié)-自定義類型詳解(結構體+枚舉+聯(lián)合),第
    發(fā)表于 07-14 08:00 ?11次下載
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>的<b class='flag-5'>進階</b>學習課件資料合集

    C語言進階】sprintf和snprintf的區(qū)別

    C語言進階】sprintf 和 snprintf 真的沒有區(qū)別嗎?
    的頭像 發(fā)表于 08-31 13:18 ?1.2w次閱讀

    C語言進階C語言指針的高階用法

    C語言進階C語言指針的高階用法
    的頭像 發(fā)表于 08-31 13:24 ?2405次閱讀

    C語言進階之嵌入式系統(tǒng)高級C語言編程

    電子發(fā)燒友網站提供《C語言進階之嵌入式系統(tǒng)高級C語言編程.rar》資料免費下載
    發(fā)表于 11-18 10:32 ?1次下載
    <b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>進階</b>之嵌入式系統(tǒng)高級<b class='flag-5'>C</b><b class='flag-5'>語言</b>編程

    C語言構建高效的嵌入式程序

    嵌入式工程師在編寫C語言程序時,需要注重效率和清晰的思路。本文將通過解析經典問題“猴子選大王”來展示如何用C語言思維方式構建
    的頭像 發(fā)表于 12-21 09:27 ?665次閱讀
    玩百家乐官网犯法| 菲律宾卡卡湾| 大发888英皇国际| 威尼斯人娱乐网| 百家乐网页游戏| 大发888娱乐场注册| 棋牌百家乐有稳赚的方法吗| 沙龙百家乐娱乐场开户注册| 利来百家乐的玩法技巧和规则 | 任你博百家乐官网的玩法技巧和规则 | 淘金百家乐的玩法技巧和规则 | 德州扑克胜率计算器| 88娱乐城2官方网站| 大厂| 顶尖百家乐官网开户| 真人百家乐官网888| 澳门百家乐官网玩法心得技巧| 百家乐官网与21点| 皇冠现金网哪个最好| 至尊百家乐| 百家乐官网稳赚打法| 百家乐官网赌场规则| 百家乐官网代理合作| 最好的百家乐博彩公司| 百家乐庄牌| 网上娱乐| 百家乐官网秘诀| 网上百家乐玩法| 真人百家乐视频| 盛京棋牌网| 百家乐官网管理启发书| 百家乐官网永利娱乐平台| 星河百家乐现金网| 新乐园百家乐娱乐城| k7线上娱乐城| 百家乐官网筹码500| 百家乐好多假网站| 大发888娱乐城赢钱| 百家乐官网代理在线游戏可信吗网上哪家平台信誉好安全 | 冠赌球网| 百家乐官网太阳城线上|