可變參數宏的原理及作用

有什麼作用呢?


主要是爲了方便管理軟件中的打印信息。我們在寫代碼或者修改bug時通常會將一些重要參數打印出來,方便我們debug,但是軟件發行的時候通常我們不希望有這些打印,可變參數宏就可以在這裏大顯身手,當然也可以用分級控制(ERR、INFO/ WARNING  DEBUG)的方式來管理,實現起來也不麻煩,只要在這個宏中添加判斷語句就可以。

但是一般我們調試問題,不會把所有打印都打開,因爲工程具有一定規模的時候,打印非常多;通常我們只打開某個文件或者模塊的打印,這時可以再對應模塊中添加變了或者宏來控制打印。


常用的有2種方式:

#define DEBUG_PRINT(fmt,args...) do{printf(fmt"\r", ##args);}while(0)

#define DEBUG_PRINT(fmt, ...) do {printf(fmt"\r",  ##__VA_ARGS__);}while(0)

效果一樣的, 下面就來分析一下這個原理:


1. 首先我們需要知道,可變參數宏是在C99標準中才實現的,以前沒定義這個 __VA_ARGS__宏,這個宏就代表可變參數列表,在GCC中  也支持args...這種寫法。  

2. 關於do {...}while(0) 的用處多多,其中一個就是防止宏展開後,代碼出問題。

例如, if(true) PRINTF   如果這時printf中含有2兩以上代碼,那麼就會導致只能執行第一條。

3. ##  這個符號在宏定義中的作用是連接字符串,會忽略前後的空格, 如  A ## B   宏展開後爲  AB。 這裏加##字符串式爲了解決在__VA_ARGS__爲空時,後面多出來一個逗號的問題。個人猜測, ##連接符會將逗號與字符串鏈接,發現字符串爲空,因此就刪除其中的逗號,因爲__VA_ARGS__這個宏裏面,本身就是有可能包含任意多個逗號來支持多個參數

4. fmt "\r"   這裏\r  是爲了兼容windows下換行符。

fmt 就是前面的第一個參數 ,是一個字符串裏面可以包含格式控制符, 這裏宏展開後 fmt 會直接展開成printf的第一個參數。然後在printf函數中這個字符串和“\r”會自動連接成一個字符串。(這個字符串連接功能的具體實現不知道是不是在printf函數中


5. 關於宏展開我們可以再編譯時指定  -E參數 就可以查看到宏展開後的代碼。


如: gcc -E input.c  -o ouput.i

查看ouput.i 就可以發現宏展開後的是什麼樣子


舉個例子:

/**********************************sum.c********************************************/


#include <stdio.h>


#ifdef DEBUG

#define DEBUG_PRINT(fmt,args...) do{printf(fmt"\r", ##args);}while(0)

#else

#define DEBUG_PRINT(fmt,args...) do{/*printf(fmt"\r", ##args)*/;}while(0)

#endif

int sum(int a, int b);

int main()

{

int result = 0;

result = sum(1, 2);

printf("result = %d\n", result);

return 0;

}


int sum(int a, int b)

{

DEBUG_PRINT("a = %d, b = %d\n", a, b);

return a+b;

}


/**********************************end********************************************/

當這個文件有幾百行幾千行的時候裏面可以有很多打印信息,我們可以通過DEBUG宏來控制打印信息是否顯示出來。

這樣當關閉DEBUG宏時也不會有警告信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章