printf 宏 调试技巧
1 前言
printf調試是嵌入式調試的基本手段,而且是非常重要的手段,我認為相比單步調試更加有用有效,特別是單片機之后跑系統,單步調試效率更加低下了,我們在工作遇到bug的時候,我們第一時間就想知道那些該死的日志有沒有保存下來,這樣好讓我們程序員裝逼一波把問題解決。
printf宏定義調試非常重要,有些日志在開發的時候才需要打開,發布的時候需要關閉,但是在代碼上又需要保留下次調試,所以我們在調試的時候才打開調試宏定義,而且printf會占用空間,很多芯片的空間非常有限,更應該關閉調試宏。
下面就直接進入正題,說一下調試的技巧
?
2. 正文
?
1 編譯器內置宏
先介紹幾個編譯器內置的宏定義,這些宏定義不僅可以幫助我們完成跨平臺的源碼編寫,靈活使用也可以巧妙地幫我們輸出非常有用的調試信息。
ANSI C標準中有幾個標準預定義宏(也是常用的):
__LINE__:在源代碼中插入當前源代碼行號;
__FILE__:在源文件中插入當前源文件名;
__DATE__:在源文件中插入當前的編譯日期
__TIME__:在源文件中插入當前編譯時間;
__STDC__:當要求程序嚴格遵循ANSI C標準時該標識被賦值為1;
__cplusplus:當編寫C++程序時該標識符被定義。
編譯器在進行源碼編譯的時候,會自動將這些宏替換為相應內容。
?
2 最基本的用法
打開宏的時候輸出
?
?
關閉宏的時候輸出
?
?
3 換個高級的用法
????? ? 代碼如下
#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?
在線編譯器網址:https://tool.lu/coderunner/
?
?4 ## __VA_ARGS__ ... 宏和可變參數
在GNU C中,宏可以接受可變數目的參數,就象函數一樣
例如:?
#define?pr_debug(fmt,arg...)?\? printk(KERN_DEBUG?fmt,?##arg)用可變參數宏(variadic macros)傳遞可變參數表?
你可能很熟悉在函數中使用可變參數表,如:
直到最近,可變參數表還是只能應用在真正的函數中,不能使用在宏中。
C99編譯器標準允許你可以定義可變參數宏(variadic macros),這樣你就可以使用擁有可以變化的參數表的宏。可變參數宏就像下面這個樣子:
#define?debug(...)?printf(__VA_ARGS__)缺省號代表一個可以變化的參數表。使用保留名 __VA_ARGS__ 把參數傳遞給宏。當宏的調用展開時,實際的參數就傳遞給 printf()了
例如:?
debug("Y?=?%d\n",?y);而處理器會把宏的調用替換成:?
printf("Y?=?%d\n",?y);因為debug()是一個可變參數宏,你能在每一次調用中傳遞不同數目的參數:?
debug("test");//?一個參數用GCC和C99的可變參數宏, 更方便地打印調試信息
可變參數宏不被ANSI/ISO C++ 所正式支持。因此,你應當檢查你的編譯器,看它是否支持這項技術。?
可變參數的宏里的'##'操作說明帶有可變參數的宏(Macros with a Variable Number of Arguments)?
更詳細請查看如下鏈接
http://www.cnblogs.com/alexshi/archive/2012/03/09/2388453.html
?
?5 舉個栗子-Linux內核調試宏
?
下面是Android touchscreen驅動的調試宏用法,看這樣的寫法就是一個大神了,給大家借鑒。
//?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)拉大家進微信技術討論群
?
?
歡迎關注微信公眾號-嵌入式Linux
?
總結
以上是生活随笔為你收集整理的printf 宏 调试技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CPU是如何访问到内存的?
- 下一篇: 史上最全面“完美商业计划书”攻略和技巧(