1. 程式人生 > >printf 巨集 除錯技巧

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