不少東西已經記不起來了,想到一點寫一點,碰到一點寫一點,慢慢累積。函數
關於#spa
#在宏定義中用於替換傳入變量的字符,例如: #define whole_operation(n) do { printf(#n "=%d\n", (n));} while(0);接口
調用whole_operation(5*6), 輸出:5*6=30, 有助於增長輸出的可讀性。io
關於##ast
##是c99中定義的用於粘連兩個符號,標識符或參數。例如:#define name_index(index) name_##index變量
調用name_index(1),則生成name_1變量, 因此不少時候##用於動態的調用標識符具備必定規律的函數,宏或者變量。防火牆
舉個列子,若是如今有add_arg_1(), add_arg_2()兩個函數,只有在運行時才知道調用哪一個函數,那麼可使用以下代碼:gc
#define call_add_arg(argc) add_arg_##argc()程序
IPnet的log模塊中,由於log級別不一樣而log級別的前幾個標識符都是IPCOM_LOG_,因此採用IPCOM_LOG_##x的方式在運行是判斷須要輸出什麼級別的log。call
關於不定參數...
好久之前在防火牆上作log模塊的時候,用到一個比較有意思的trick。由於log要接收不一樣模塊的不一樣信息,可是每一個模塊都含有本身獨特的信息,爲了保證全部信息都能被log接受,當時用了不定參的函數做爲log的接口log(msgid, ...),經過va_list ap; va_start(ap, firstarg); va_arg(ap, type);va_end(ap);的方式來接受傳入的各個參數。事實上,大多數prinf也是經過這個方式實現。 可是這種方式的函數調用容易出問題, 函數不知道何時參數結束,有可能致使程序崩潰。
C99定義了__VA_ARGS__ 用於接受不定參數的宏:#define LOG(msgid, ...) log(msgid, __VA_ARGS__, lastarg) 或者#define LOG(msgid, arg...) log(msgid, arg, lastarg) lastarg是預約義的用於標識結束的宏或變量, 若不用__VA_ARGS__,則需用arg...來替代。 這樣,LOG函數就能夠接受任意多1個以上參數而不須要關係何時結束。那麼若是LOG調用時只有一個msgid參數,就會變成log(msgid,,lastarg),這時候就須要藉助##的另外一個做用,若是##,後面沒有參數,那麼逗號就會被省略,因而LOG函數的最終定義變成: #define LOG(msgid, ...) log(msgid, ##__VA_ARGS__, lastarg)