我們一般在Debug需要列印調試資訊的時候,需要可變參數的宏。
一, vc(C99)的複雜宏。
參考msdn(http://msdn2.microsoft.com/en-us/library/ms177415.aspx )。使用這種複雜宏時,省略号是格式控制參數,而辨別符__VA_ARGS__用來插入另外的參數。__VA_ARGS__ 将"..." 傳遞給宏。
例如:
#include <stdio.h>
#define CHECK1(x, ...) if (!(x)) { printf(__VA_ARGS__); }
#define CHECK2(x, ...) if ((x)) { printf(__VA_ARGS__); }
#define CHECK3(...) { printf(__VA_ARGS__); }
int main( )
{
CHECK1(0, "here %s %s %s", "are", "some", "varargs1(1)/n");
CHECK1(1, "here %s %s %s", "are", "some", "varargs1(2)/n"); // won't print
CHECK2(0, "here %s %s %s", "are", "some", "varargs2(3)/n"); // won't print
CHECK2(1, "here %s %s %s", "are", "some", "varargs2(4)/n");
CHECK3("here %s %s %s", "are", "some", "varargs3(5)/n");
return 0;
}
輸出為:
here are some varargs1(1)
here are some varargs2(4)
here are some varargs3(5)
二,GCC中的複雜宏
GCC支援C99中的複雜宏,但G++不支援。GCC使用一種不同的文法,給可變參數一個名字,如同其它參數一樣。
#define CHECK1(x,format, args...) if(x) { printf (format, args); }
顯然這樣易于描述而且可讀性更強。
三,CHECK("Some messges.")的情況
這時由于宏展開後有個多餘的逗号,,将導緻編譯錯誤.。為了解決這個問題,CPP使用一個特殊的“##”操作。
#define CHECK(format, ...) printf ( format, ## __VA_ARGS__)
這裡,如果可變參數被忽略或為空,“##”操作将使預處理器去除掉它前面的那個逗号。如果在宏調用時,确實提供了一些可變參數,GNU CPP也會工作正常,它會把這些可變參數放到逗号的後面。
四,類似printf()的技巧
用一個被括弧括起來的 “參數”來定義和調用宏,參數在宏擴充的時候成為類似printf()函數中的格式控制字元串那樣的參數清單。
#define CHECK(args) (printf("DEBUG: "), printf(args))
用了括号。
/
今天來說說宏。什麼?宏也能可變參數?是的,你沒有聽錯,帶參數的宏和函數一樣,同樣支援可變參數。下面通過一個小程式加以說明。
#include
#include
#define OUTSCREEN(msg, ...) printf(msg,__VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!n%s", "__This is a MACRO!n");
return 0;
}
這個可變參數的宏是新的C99規範中新增的,目前似乎隻有gcc支援(VC6.0的編譯器不支援)。
#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!n%s", "__This is a MACRO!n");
return 0;
}
假如我們将上面的代碼稍作一下修改,變成下面的樣子。
#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)
int main(int argc, char* argv[])
{
OUTSCREEN("Hello World!");
return 0;
}
注意我僅僅是将main函數裡的OUTSCREEN做了修改,這時可變參數的個數為0了。但是編譯的時候gcc卻報錯:
In function `main':
error: parse error before ')' token
什麼原因導緻出錯呢?把宏展開一下看看,原來是","惹得禍。那麼這種參數個數可以為0的宏要怎麼寫呢?C99的規範沒有定義這個,gcc對此做了擴充。重新定義OUTSCREEN宏如下:
#define OUTSCREEN(msg, ...) printf(msg, ##__VA_ARGS__)
當可變參數的個數為0時,這裡的##起到把前面多餘的","去掉,實際上變成了printf(msg),這樣編譯就能通過了。
另外,__VA_ARGS__這個宏實在不利于記憶,gcc對此做了擴充,另一種可接受的定義方法為:
#define OUTSCREEN(msg, args...) printf(msg, ##args)