在系統在整合或移值時最常用的就是以巨集來置換一些底層 function. 這類的技巧叫 wrapper (意思是包裝紙)

但是在面對像 printf() 或者 scanf() 之類參數個數可變 (或稱不具名參數) 的函數, 就出現只能更換函數名稱, 而無法增減參數個數的冏境, 例如:

// 下例 OK, 但是無法處理參數的異動
#define printf             my_printf

// 下例 OK, 但是只能處理剛好二個參數的異動 (增加, 交換)
#define printf(a, b)       my_printf(x, b, a)

// 下例 ERR, C 編譯器的 preprocessor 不認識 ...
#define printf(a, b, ...)  my_printf(x, a, b, ...)

下面這二種用法在 GNU GCC 或者符合 C99 標準的 C 編譯器 preprocessor 有支援.

// C99 Standard
#define printf(fmt, ...)       my_printf(fmt, __VA_ARGS__)

// GCC old style
#define printf(a, b, args...)  my_printf(x, b, a, args)


這個問題, 如果限定只能使用 #define, 而且 C 編譯器的 preprocessor 又不支援的話目前所知是無解的.

看過有人使用第二組括號來將變動參數括住, 好讓 preprocessor 把它當成一個參數而已, 但限制是程式一開始就要換一個寫法, 所以只能處理自己寫的程式, 想要快速移植別人的程式就不管用了.

#define DEGUG(FORMAT,ARGS)    printf(FORMAT, ARGS)

DEBUG("%s = %f\n", ("x",0) );

// 上一行替換後相當於這樣
printf("%s = %f\n", "x", 0 );

下面的例子也是利用兩組括號的技巧

#if (DEBUG)
    #define DBGMSG(x) { printf x; }
#else
    #define DBGMSG(x)
#endif

DBGMSG(("msg format %d, %X", a, b));

// DEBUG 為假時, 上一行會替換空白行
// DEBUG 為真時, 會替換後相當於這樣
printf("msg format %d, %X", a, b);

如果不限定只用 #define, 則我們可以使用 stdarg.h 來處理變動的參數. 請參考這篇

    MagicJackTing 發表在 痞客邦 留言(0) 人氣()