printf 宏 调试技巧
1 前言
printf調(diào)試是嵌入式調(diào)試的基本手段,而且是非常重要的手段,我認(rèn)為相比單步調(diào)試更加有用有效,特別是單片機(jī)之后跑系統(tǒng),單步調(diào)試效率更加低下了,我們?cè)诠ぷ饔龅絙ug的時(shí)候,我們第一時(shí)間就想知道那些該死的日志有沒(méi)有保存下來(lái),這樣好讓我們程序員裝逼一波把問(wèn)題解決。
printf宏定義調(diào)試非常重要,有些日志在開(kāi)發(fā)的時(shí)候才需要打開(kāi),發(fā)布的時(shí)候需要關(guān)閉,但是在代碼上又需要保留下次調(diào)試,所以我們?cè)谡{(diào)試的時(shí)候才打開(kāi)調(diào)試宏定義,而且printf會(huì)占用空間,很多芯片的空間非常有限,更應(yīng)該關(guān)閉調(diào)試宏。
下面就直接進(jìn)入正題,說(shuō)一下調(diào)試的技巧
?
2. 正文
?
1 編譯器內(nèi)置宏
先介紹幾個(gè)編譯器內(nèi)置的宏定義,這些宏定義不僅可以幫助我們完成跨平臺(tái)的源碼編寫(xiě),靈活使用也可以巧妙地幫我們輸出非常有用的調(diào)試信息。
ANSI C標(biāo)準(zhǔn)中有幾個(gè)標(biāo)準(zhǔn)預(yù)定義宏(也是常用的):
__LINE__:在源代碼中插入當(dāng)前源代碼行號(hào);
__FILE__:在源文件中插入當(dāng)前源文件名;
__DATE__:在源文件中插入當(dāng)前的編譯日期
__TIME__:在源文件中插入當(dāng)前編譯時(shí)間;
__STDC__:當(dāng)要求程序嚴(yán)格遵循ANSI C標(biāo)準(zhǔn)時(shí)該標(biāo)識(shí)被賦值為1;
__cplusplus:當(dāng)編寫(xiě)C++程序時(shí)該標(biāo)識(shí)符被定義。
編譯器在進(jìn)行源碼編譯的時(shí)候,會(huì)自動(dòng)將這些宏替換為相應(yīng)內(nèi)容。
?
2 最基本的用法
打開(kāi)宏的時(shí)候輸出
?
?
關(guān)閉宏的時(shí)候輸出
?
?
3 換個(gè)高級(jí)的用法
????? ? 代碼如下
#include?<stdio.h>#define?__DEBUG__#ifdef?__DEBUG__
#define?DEBUG(format,...)?printf("Date:?"__DATE__",File:?"__FILE__",?Line:?%05d:?"format"\n",?__LINE__,?##__VA_ARGS__)
#else
#define?DEBUG(format,...)
#endifint?main(int?argc,?char?**argv)?{char?str[]="Hello?World";DEBUG("%s",str);return?0;
}
?
輸出如下
Date:?Oct??5?2018,File:?/code/main.c,?Line:?00013:?Hello?World sandbox>?exited?with?status?0?
在線編譯器網(wǎng)址:https://tool.lu/coderunner/
?
?4 ## __VA_ARGS__ ... 宏和可變參數(shù)
在GNU C中,宏可以接受可變數(shù)目的參數(shù),就象函數(shù)一樣
例如:?
#define?pr_debug(fmt,arg...)?\? printk(KERN_DEBUG?fmt,?##arg)用可變參數(shù)宏(variadic macros)傳遞可變參數(shù)表?
你可能很熟悉在函數(shù)中使用可變參數(shù)表,如:
直到最近,可變參數(shù)表還是只能應(yīng)用在真正的函數(shù)中,不能使用在宏中。
C99編譯器標(biāo)準(zhǔn)允許你可以定義可變參數(shù)宏(variadic macros),這樣你就可以使用擁有可以變化的參數(shù)表的宏。可變參數(shù)宏就像下面這個(gè)樣子:
#define?debug(...)?printf(__VA_ARGS__)缺省號(hào)代表一個(gè)可以變化的參數(shù)表。使用保留名 __VA_ARGS__ 把參數(shù)傳遞給宏。當(dāng)宏的調(diào)用展開(kāi)時(shí),實(shí)際的參數(shù)就傳遞給 printf()了
例如:?
debug("Y?=?%d\n",?y);而處理器會(huì)把宏的調(diào)用替換成:?
printf("Y?=?%d\n",?y);因?yàn)閐ebug()是一個(gè)可變參數(shù)宏,你能在每一次調(diào)用中傳遞不同數(shù)目的參數(shù):?
debug("test");//?一個(gè)參數(shù)用GCC和C99的可變參數(shù)宏, 更方便地打印調(diào)試信息
可變參數(shù)宏不被ANSI/ISO C++ 所正式支持。因此,你應(yīng)當(dāng)檢查你的編譯器,看它是否支持這項(xiàng)技術(shù)。?
可變參數(shù)的宏里的'##'操作說(shuō)明帶有可變參數(shù)的宏(Macros with a Variable Number of Arguments)?
更詳細(xì)請(qǐng)查看如下鏈接
http://www.cnblogs.com/alexshi/archive/2012/03/09/2388453.html
?
?5 舉個(gè)栗子-Linux內(nèi)核調(diào)試宏
?
下面是Android touchscreen驅(qū)動(dòng)的調(diào)試宏用法,看這樣的寫(xiě)法就是一個(gè)大神了,給大家借鑒。
//?Log?define #define?GTP_ERROR(fmt,arg...)??????????printk("<<-GTP-ERROR->>?"fmt"\n",##arg) #if?DEBUG_SWITCH #define?GTP_INFO(fmt,arg...)???????????printk("<<-GTP-INFO->>?"fmt"\n",##arg) #define?GTP_DEBUG(fmt,arg...)??????????do{\if(GTP_DEBUG_ON)\printk("<<-GTP-DEBUG->>?[%d]"fmt"\n",__LINE__,?##arg);\}while(0) #define?GTP_DEBUG_ARRAY(array,?num)????do{\s32?i;\u8*?a?=?array;\if(GTP_DEBUG_ARRAY_ON)\{\printk("<<-GTP-DEBUG-ARRAY->>\n");\for?(i?=?0;?i?<?(num);?i++)\{\printk("%02x???",?(a)[i]);\if?((i?+?1?)?%10?==?0)\{\printk("\n");\}\}\printk("\n");\}\}while(0) #define?GTP_DEBUG_FUNC()???????????????do{\if(GTP_DEBUG_FUNC_ON)\printk("?????<<-GTP-FUNC->>???????Func:%s@Line:%d\n",__func__,__LINE__);\}while(0)#else #define?GTP_INFO(fmt,arg...) #define?GTP_DEBUG(fmt,arg...) #define?GTP_DEBUG_ARRAY(array,?num) #define?GTP_DEBUG_FUNC() #endif?
?
?
歡迎加我微信(weiqifa0)拉大家進(jìn)微信技術(shù)討論群
?
?
歡迎關(guān)注微信公眾號(hào)-嵌入式Linux
?
總結(jié)
以上是生活随笔為你收集整理的printf 宏 调试技巧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CPU是如何访问到内存的?
- 下一篇: 史上最全面“完美商业计划书”攻略和技巧(