日誌輸出可變引數巨集的使用記錄
阿新 • • 發佈:2020-10-28
#define COLOR_RED "\033[1, 31m" #define COLOR_NONE "\033[0m"
#if DEBUG #define DBG_PRT(fmt, args...)\ do\ {\ printf(COLOR_RED"file:%s line:%s", __FILE__, __LINE__);\ printf(fmt,##args);\ }while(0)
#else
#define DGB_PRT(fmt, args...)
#endif
上述程式碼是在嵌入式日誌列印中常用的巨集函式,這個巨集列印函式可以顯示列印資訊所在的檔案、行數、函式名等一些你需要的資訊。另外需要注意的是,在巨集定義中儘量使用do while(0)結構來包含內容,如果用花括號{}來包含往往會出現一些錯誤,比如我將上述程式碼改成小面用花括號包含的形式:
#define DBG_PRT(fmt, args...)\ {\ printf(COLOR_RED"file:%s line:%s", __FILE__, __LINE__);\ printf(fmt, ##args);\ } if (1) DGB_PRT("hello world"); 展開後為: if (1) { printf(COLOR_RED"file:%s line:%s", __FILE__, __LINE__);printf(args); };-->這裡會有一個;號,會有語法錯誤
上述DGB_PRT(fmt, args...)定義中, “...”符號表示的是可變引數,args...的寫法表示在後續的使用中
可以用args識別符號表示可變引數列表,然後在後面的巨集定義中,直接使用 args 代表變參列表就可以了。
我們在識別符號args 前面加上巨集連線符 ##,這樣做的好處是,當變參列表非空時,## 的作用是連線 fmt,和變參列表,
各個引數之間用逗號隔開,巨集可以正常使用;當變參列表為空時,## 還有一個特殊的用處,它會將固定引數 fmt 後面的逗號刪除掉,
這樣巨集也就可以正常使用了。
可變引數巨集的另外兩種寫法
第一種,使用__VA_ARGS__表示可變引數列表
#define DBG_PRT(fmt, ...)\ do\
{\ printf(COLOR_RED"file:%s line:%s", __FILE__, __LINE__);\ printf(fmt, ##__VA_ARGS__);\ }while(0)
第二種寫法比較簡潔,直接將可變引數列表...和fmt識別符號連在一起,這樣後續使用的時候直接使用fmt識別符號,這個識別符號就同時包含了格式化字串和可變引數列表,同時可以應對引數為空的情形,因為可變引數列表和fmt是連線在一起的,可變引數列表為空時,最後fmt表示的內容就只有格式化字串了。
#define DBG_PRT(fmt...)\ do\ {\ printf(COLOR_RED"file:%s line:%s", __FILE__, __LINE__);\ printf(fmt);\ }while(0)
另外記錄一下#和##的使用方法(參考https://blog.csdn.net/baidu_33850454/article/details/79363033)
使用#把巨集引數變為一個字串——字串化操作符
用##把兩個巨集引數貼合在一起——字元連線操作符
一般用法
#include<cstdio> #include<climits> using namespace std; #define STR(s) #s #define CONS(a,b) int(a##e##b) int main() { printf(STR(vck)); // 輸出字串"vck" printf("%d\n", CONS(2,3)); // 2e3 輸出:2000 return 0; }
注意: 當巨集引數是另一個巨集的時候,需要注意的是凡巨集定義裡有用’#’或’##’的地方巨集引數是不會再展開.
即, 只有當前巨集生效, 引數裡的巨集!不!會!生!效 !!!!
#define A (2) #define STR(s) #s #define CONS(a,b) int(a##e##b) printf("int max: %s\n", STR(INT_MAX)); // INT_MAX # printf("%s\n", CONS(A, A)); // compile error --- int(AeA) 展開後: printf("int max: %s\n","INT_MAX"); printf("%s\n", int(AeA));
由於A和INT_MAX均是巨集,且作為巨集CONS和STR的引數,並且巨集CONS和STR中均含有#或者##符號,所以A和INT_MAX均不能被解引用。導致不符合預期的情況出現。
解決這個問題的方法很簡單. 加多一層中間轉換巨集. 加這層巨集的用意是把所有巨集的引數在這層裡全部展開,那麼在轉換巨集裡的那一個巨集(_STR)就能得到正確的巨集引數.
#define A (2)
#define _STR(s) #s
#define STR(s) _STR(s) // 轉換巨集
#define _CONS(a,b) int(a##e##b)
#define CONS(a,b) _CONS(a,b) // 轉換巨集
printf("int max: %s\n",STR(INT_MAX));
//輸出為: int max:0x7fffffff
//STR(INT_MAX) --> _STR(0x7fffffff)
然後再轉換成字串; printf("%d\n", CONS(A, A));
//輸出為:200
//CONS(A, A) --> _CONS((2), (2)) --> int((2)e(2))