2009-08-25 61 views
3

我有一個可變參數函數它打印在我的申請的錯誤消息,其代碼在下面給出:如何將變量參數轉換爲宏?

void error(char *format,...) 
{ va_list args; 
    printf("Error: "); 
    va_start(args, format); 
    vfprintf(stderr, format, args); 
    va_end(args); 
    printf("\n"); 
    abort(); 
} 

該函數在錯誤條件下使用,如下所示:

error("invalid image width %d and image height %d in GIF file %s",wid,hei,name); 

error()功能是從具有不同參數的不同地方調用(可變參數函數)。

函數方法正常工作。

現在,如果我有這個功能轉換成一個宏,我該怎麼辦呢?我試圖這樣做:

#define error(format) {va_list args;\ 
    printf("Error: ");\ 
    va_start(args, format);\ 
    vfprintf(stderr, format, args);\ 
    va_end(args);\ 
    printf("\n"); abort()} 

但是,這不會正確打印參數。

上面的宏定義有什麼問題?

什麼是修復?

回答

2

如果你的編譯器支持ISO風格複雜的宏,你可以定義一個宏這樣:

#define error(...) \  
    fprintf(stderr, "Error: "); \ 
    fprintf(stderr, __VA_ARGS__); \ 
    fprintf(stderr, "\n"); \ 
    abort(); 

另外,如果你正在使用gcc,也就是作爲這樣的GNU風格的可變參數宏:

#define error(format, args...) \  
    fprintf(stderr, "Error: "); \ 
    fprintf(stderr, format , ## args); \ 
    fprintf(stderr, "\n"); \ 
    abort(); 

欲瞭解更多信息,請參閱http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

更新

如果你的編譯器不具有可變參數宏的支持,一個(窮?)替代方法是堅持va_list函數的方法。如果你希望定義駐留在頭文件中,那麼可能是一個靜態內聯函數?

static inline void error(const char *fmt, ...) { 
#define PRINT_ERROR 
    va_list args; 
    fprintf(stderr, "Error: "); 
    va_start(args, fmt); 
    vfprintf(stderr, fmt, args); 
    va_end(args); 
    fprintf(stderr, "\n"); 
    abort(); 
#endif 
} 
+0

@shawnchin:謝謝。我在MSVC6.0,MSVS-2005編譯器中試過,它似乎不支持可變參數宏。我猜GCC支持,但是你知道任何基於Windows的編譯器支持嗎? – goldenmean 2009-08-25 12:32:40

+0

@goldenmean:此網站說MSVS-2005 Visual C++中引入了ISO風格的可變參數宏(http://msdn.microsoft.com/en-us/library/ms177415(VS.80).aspx) – 2009-08-25 12:47:15

+0

@shawnchin:是否有任何特殊的MSVisual Studio項目選項需要設置,以使編譯器能夠編譯此可變宏。我嘗試設置幾個選項(例如將代碼編譯爲C++)是否有任何宏強制編譯器接受這些可變宏擴展(它們是C99擴展)? – goldenmean 2009-08-25 13:19:13

0

宏沒有(還?)支持可變參數,反正使用va_list在這裏不起作用,它只適用於可變參數函數參數。

你爲什麼想反正與宏替換函數(正常工作,根據你)?

1

這裏是一個article with some examples on variable arguments used in a macro。它看起來應該做你想要的。您可以在宏中使用__VA_ARGS__

您正在使用哪種編譯器?

+0

看起來它會工作正常。但是爲什麼用一個宏替換一個完美的函數調用?這不像代碼在這種情況下會對性能或任何事情產生影響。這只是採取一些體面的代碼,並將其變成廢話代碼 – Glen 2009-08-25 12:24:38

0

許多編譯器支持GNU樣式複雜的宏,就像這樣:

#define error(format,args...) do { \ 
    fprintf(stderr, "error: " format "\n", ##args); \ 
    abort(); \ 
} while(0) 

但是,如果你的目標是爲便攜性,不使用複雜的宏。

+0

@拉爾塔:謝謝。我在MSVC6.0,MSVS-2005編譯器中試過,它似乎不支持可變參數宏。我猜GCC支持,但是你知道任何基於Windows的編譯器支持嗎? – goldenmean 2009-08-25 12:32:01

+0

我在Metrowerks CodeWarrior和Windows上的各種GCC上使用了這個構造。 – laalto 2009-08-25 12:56:22

0

有,你想要做什麼常見的擴展,簡單的寫:

#define error(args...) (fputs("Error: ",stdout),printf(args),puts("")) 

C99用戶也可以說:

#define error(...) (fputs("Error: ",stdout),printf(__VA_ARGS__),puts("")) 

但也有some problems使用__VA_ARGS__。幸運的是有一個GCC擴展來處理它,但是隨後你又回到了使用編譯器特定的擴展,並且args...模式更爲廣泛的可用。