天天看點

可變參數宏 , Variadic Macros

 我們一般在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)

繼續閱讀