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,...) #endif int 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)傳遞可變引數表
你可能很熟悉在函式中使用可變引數表,如:
void printf(const char* format, ...);
直到最近,可變引數表還是隻能應用在真正的函式中,不能使用在巨集中。
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:%[email protected]:%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