色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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

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

3天內不再提示

使用宏定義來封裝一個宏打印函數

Q4MP_gh_c472c21 ? 來源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2022-04-18 14:32 ? 次閱讀

宏打印函數

在我們的嵌入式開發中,使用printf打印一些信息是一種常用的調試手段。但是,在打印的信息量比較多的時候,就比較難知道哪些信息在哪個函數里進行打印。

特別是對于異常情況的打印,我們需要快速定位到異常情況的位置。

這時候我們可以使用宏定義來封裝一個宏打印函數,這個宏打印函數可以顯示打印信息所在的文件、行數、函數名等信息。如:

#defineDBG_PRINTF(fmt,args...)
{
printf("<>",__FILE__,__LINE__,__FUNCTION__);
printf(fmt,##args);
}

使用范例:

c69d846a-bed7-11ec-9e50-dac502259ad0.png

c6af7eea-bed7-11ec-9e50-dac502259ad0.png

可見,使用方法與printf的使用方法一樣,而且每條打印語句開頭都會打印調試信息所在的文件名、行號、函數名信息,方便我們查找一些調試信息。

其中,__FILE____LINE____FUNCTION__這三個宏是編譯器內置宏定義,分別代表調試信息所在文件、行號、函數。

除此之外,常用的宏還有:__DATE____TIME__,分別代表當前的編譯日期與時間。如:

DBG_PRINTF("Compile Time: %s  %s
", __DATE__, __TIME__);

c6bb87da-bed7-11ec-9e50-dac502259ad0.png

第二條printf中的##符號是為了處理args不代表任何參數的情況。如:

DBG_PRINTF("Hello world");

當不加##符號是,以上宏的第二條語句被拓展為:

printf("Helloworld
",);

可見,多出了一個逗號,這個逗號是多余的。

加上##符號后,以上宏的第二條語句被拓展為:

printf("Helloworld
");

這才是我們想要的結果。其實這些結果我們通過查看預處理文件可以清晰的知道:

c6c4f50e-bed7-11ec-9e50-dac502259ad0.png

c6ce38b2-bed7-11ec-9e50-dac502259ad0.png

c6e0a24a-bed7-11ec-9e50-dac502259ad0.png

最后需要注意的是,這個DBG_PRINTF還是與printf不一樣的。DBG_PRINTF宏是兩條語句的組合,無返回值;而printf的原型是:

intprintf(constchar*__format,...)

但是我們一般都很少使用printf的返回值,所以DBG_PRINTF的用法與printf函數基本一致。

打印調試宏開關

通常情況下,一些打印調試信息只是在我們調試階段需要的,在程序發布階段是不需要的。

所以,為了避免打印調試信息帶來的資源開銷,我們可以把這些打印調試語句給注釋掉。

一種方法是逐句進行注釋,這是一種比較低效的方法。比較高效的方法就是添加調試宏開關,利用條件編譯來選擇打印/不打印調試信息。

比如我們可以把上面的代碼改造為:

#defineDEBUG1

#ifDEBUG
#defineDBG_PRINTF(fmt,args...)
{
printf("<>",__FILE__,__LINE__,__FUNCTION__);
printf(fmt,##args);
}
#else
#defineDBG_PRINTF(fmt,args...)
#endif

根據DEBUG宏的值來選擇對應的打印宏函數。當DEBUG的值為1時啟動相關的打印調試語句,DEBUG的值為0時則關閉打印調試語句。

這樣我們就可以很方便的通過設置DEBUG宏的值來啟動與關閉我們整個工程的DBG_PRINTF打印調試信息。

do{}while(0)

其實,上面我們封裝的打印宏DBG_PRINTF還有一點缺陷,比如我們與if、else使用的時候,會有這樣的一種使用情況:

c6e8e662-bed7-11ec-9e50-dac502259ad0.png

此時會報語法錯誤。為什么呢?

同樣的,我們可以先來看一下我們的demo代碼預處理過后,相應的宏代碼會被轉換為什么。如:

c6f062a2-bed7-11ec-9e50-dac502259ad0.png

這里我們可以看到,我們的if、else結構代碼被替換為如下形式:

if(c)
{/*.......*/};
else
{/*.......*/};

顯然,出現了語法錯誤。if之后的大括號之后不能加分號,這里的分號其實可以看做一條空語句,這個空語句會把if與else給分隔開來,導致else不能正確匹配到if,導致語法錯誤。

為了解決這個問題,有幾種方法。第一種方法是:把分號去掉。代碼變成:

c6fa21d4-bed7-11ec-9e50-dac502259ad0.png

第二種方法是:在if之后使用DBG_PRINTF打印調試時總是加{}。代碼變成:

c7086424-bed7-11ec-9e50-dac502259ad0.png

以上兩種方法都可以正常編譯、運行了。

但是,我們C語言中,每條語句往往以分號結尾;并且,總有些人習慣在if判斷之后只有一條語句的情況下不加大括號;而且我們創建的DBG_PRINTF宏函數的目的就是為了對標printf函數,printf函數的使用加分號在任何地方的使用都是沒有問題的。

基于這幾個原因,我們有必要再對我們的DBG_PRINTF宏函數進行一個改造。

下面引入do{}while(0)來對我們的DBG_PRINTF進行一個簡單的改造。改造后的DBG_PRINTF宏函數如下:

#define DBG_PRINTF(fmt, args...)  
do
{
    printf("<> ", __FILE__, __LINE__, __FUNCTION__);
    printf(fmt, ##args);
}while(0)

這里的do...while循環的循環體只執行一次,與不加循環是效果一樣。并且,可以避免了上面的問題。預處理文件:

c713cc2e-bed7-11ec-9e50-dac502259ad0.png

我們的宏函數實體中,while(0)后面不加分號,在實際調用時補上分號,既符合了C語言語句分號結尾的習慣,也符合了do...while的語法規則。

使用do{}while(0)來封裝宏函數可能會讓很多初學者看著不習慣,但必須承認的是,這確確實實是一種很常用的方法。

STM32的HAL庫中搜索while(0):

c71d7bac-bed7-11ec-9e50-dac502259ad0.png

c732df88-bed7-11ec-9e50-dac502259ad0.png

Linux源碼中搜索while(0):

c743e38c-bed7-11ec-9e50-dac502259ad0.png

可見,在實際應用中,do{}while(0)用的很多。

#運算符與##運算符

這兩個運算符之前也有分享過,這里順便也提一下。

#號作為一個預處理運算符,可以把記號轉換成字符串。

例如,如果A是一個宏形參,那么#A就是轉換為字符串"A"的形參名。這個過程稱字符串化(stringizing)。以下程序演示這個過程:

c74fdd9a-bed7-11ec-9e50-dac502259ad0.jpg

c75744e0-bed7-11ec-9e50-dac502259ad0.jpg

##運算符可以把兩個記號組合成一個記號。以下程序演示這個過程:

c7642e58-bed7-11ec-9e50-dac502259ad0.jpg

c76e4a46-bed7-11ec-9e50-dac502259ad0.jpg

這個運算符用得很多。如:

c7792664-bed7-11ec-9e50-dac502259ad0.png

END 審核編輯 :李倩

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4338

    瀏覽量

    62770
  • 編譯器
    +關注

    關注

    1

    文章

    1636

    瀏覽量

    49175

原文標題:這幾個宏技巧,絕對實用!

文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    定義后面能不能加分號

    用define定義,最后需不需要加分號?
    的頭像 發表于 01-06 16:35 ?119次閱讀

    C語言中最常見的定義寫法

    如果讓你用C語言寫個定義,我相信大部分同學順手就能寫出define。
    的頭像 發表于 10-28 11:12 ?320次閱讀

    SV中define定義的用法

    SV中使用預處理指令`define定義可以用來創建文本替換。根據場景不同,`define主要用來定義常量、簡化復雜的表達式或代碼段以
    的頭像 發表于 10-21 14:22 ?663次閱讀

    開源項目!基于 Arduino DIY 漂亮的機械鍵盤

    MAKER: Giovanni Aggiustatutto 在數字化工作日益普遍的今天,擁有鍵盤無疑是提升效率的得力助手。想象下,只需輕觸
    發表于 08-19 17:02

    科技擬收購APCB 100%股權

    科技近期發布重要公告,宣布其計劃通過全資子公司新加坡勝及PSL,以不超過2.787億元人民幣的現金,全面收購APCB Electronics(Thailand)Co.,Ltd.(簡稱APCB)的100%股權。此次收購標志著勝
    的頭像 發表于 08-12 15:06 ?578次閱讀

    請問怎么在自己的工程里添加INCLUDE_xTaskGetHandle?

    你好: 我需要使用 xTaskGetHandle 這個API,但是 idf.py menuconfig進去freertos組件里沒有這個配置選項 我應該怎么添加定義到我的cma
    發表于 06-21 12:39

    請問下FREERTOS只能創建4任務,修改哪個定義可以增加創建任務的數量?

    請問下FREERTOS只能創建4任務,修改哪個定義可以增加創建任務的數量?解決方法:增加FREERTOS的堆。
    發表于 05-13 06:44

    請問#define PROXY_PORT 這種定義里面的尖括號是什么意思?

    #define PROXY_PORT這種定義里面的尖括號有什么特殊的意義嗎?
    發表于 05-09 07:28

    STemWin中GUI_NUM_LAYERS是如何進行定義的,其依據是什么?

    STemWin中GUI_NUM_LAYERS 這個層數指什么,是如何進行定義的,其依據是什么?
    發表于 04-19 06:21

    集PLC如何應用于建筑的3D打印

    集MC Pi-Prime模塊化PLC采用EtherCat作為通信協議,有助于實現快速的反應時間和精確的定位控制,為自動化工程師提供靈活的擴展與集成,并縮短實施時間,助力建筑行業引入3D打印
    的頭像 發表于 03-22 10:46 ?351次閱讀
    <b class='flag-5'>宏</b>集PLC如何應用于建筑的3D<b class='flag-5'>打印</b>?

    鑫科技即將掛牌上市

    浙江鑫科技股份有限公司(以下簡稱“鑫科技”)成功獲得證監會的批文,即將掛牌上市,這標志著鑫科技將成為資本市場鍛造鋁合金車輪第股,迎來產業經營和資本運營雙輪驅動的全新發展階段。
    的頭像 發表于 03-11 15:30 ?798次閱讀

    CubeMx生成的stm32f013vet6設備,對于SDIOCLK頻率設置的定義與手冊里面對不上是為什么?

    stm32f1xx_ll_sdmmc.h文件里面的這兩定義是針對48MHz 這里的48MHz是怎么的? 并且在進行初始化的時候會使用到這一個
    發表于 03-08 08:29

    L431想要使用hal_flash相關函數,在已經定義的情況下#ifdef判斷失敗的原因?

    芯片是L431的 在已經定義的情況下,#ifdef判斷失敗。庫有包含。
    發表于 03-07 07:42

    嵌入式Linux C語言編程程序調試與定義

    在Linux使用gcc編譯程序的時候,對于調試的語句還具有些特殊的語法。gcc編譯的過程中,會生成,可以使用這些分別打印當前源文件
    發表于 03-01 11:41 ?1063次閱讀

    如何用Rust過程魔法簡化SQL函數呢?

    這是 RisingWave 中 SQL 函數的實現。只需短短幾行代碼,通過在 Rust 函數上加行過程
    的頭像 發表于 01-23 09:43 ?994次閱讀
    如何用Rust過程<b class='flag-5'>宏</b>魔法簡化SQL<b class='flag-5'>函數</b>呢?
    主站蜘蛛池模板: japanese色系free日本| 无码日韩人妻精品久久蜜桃免费| 99久热精品免费观看| 视频成人app永久在线观看| 久久re热线视频精品99| 国产36d在线观看| 69夫妻交友网| 亚洲精品无AMM毛片| 日本亚洲中文字幕无码区| 老师的玉足高跟鞋满足我| 国产午夜视频在线| YELLOW视频在线观看大全| 尹人久久大香找蕉综合影院| 使劲别停好大好深好爽动态图| 伦理片在线线手机版韩国免费6| 国产女合集小岁9三部| xxx粗大长欧美| 稚嫩挤奶h调教h| 亚洲欧洲日产国码久在线| 色悠久久久久综合网小说| 男人叼女人| 老鸭窝毛片| 久久AV国产麻豆HD真实| 国产中的精品AV一区二区| 动漫美女禁区| XXOO麻豆国产在线九九爱| 97草碰在线视频免费| 永久午夜福利视频一区在线观看| 亚洲国产精品嫩草影院永久 | 久久er国产免费精品| 国产麻豆精品久久一二三| 国产不卡在线观看视频| 成人在线不卡视频| yw193龙物免费官网在线| 99RE8国产这里只有精品| 在线免费视频a| 亚洲一区免费在线观看| 亚洲日韩国产精品乱-久| 亚洲欧美日韩精品久久奇米色影视| 午夜看片a福利在线观看| 忘忧草在线影院WWW日本二 |