C語言中宏定義之 ## 用於可變參數


GCC 支持復雜的宏,它使用一種不同的語法,使你可以給可變參數一個名字,如同其它參數一樣,比如:

引用
#define debug(format, args...) fprintf(stderr, format, args)


這種定義可讀性更強,也更容易描述。完整測試代碼:

引用
#include <stdio.h>

#define debug(format, args...) fprintf(stderr, format, args)

int main()
{
     char a[20] = "hello world \n";
     int i = 10;
    debug("i = %d, %s", i, a);

     return 0;
}


運行輸出

引用
beyes@linux-beyes:~/C/micro> ./mic.exe 
i = 10, hello world


但是上面的定義仍存在一點問題,如果把上面的代碼改為下面的:

引用
#include <stdio.h>

#define debug(format, args...) fprintf(stderr, format, args)

int main()
{

    debug("hello world \n");

     return 0;
}


那么在編譯時會提示以下錯誤

引用
beyes@linux-beyes:~/C/micro> gcc -g mic.c -o mic.exe
mic.c: In function ‘main’:
mic.c:10: error: expected expression before ‘)’ token


提示缺少右邊括號。這是因為,當宏展開后,"hello world\n" 代入 format,然而,在其后還緊跟着一個逗號,但是這個逗號后面是期望有 args 參數的,但這里卻沒有,所以宏不能展開完全,故而無法編譯通過。那么,再改一下宏定義:

引用
#include <stdio.h>

#define debug(format, args...) fprintf(stderr, format, ##args)

int main()
{
    debug("hello world \n");

     return 0;
}


這時候,再編譯運行及輸出:

引用
beyes@linux-beyes:~/C/micro> gcc -g mic.c -o mic.exe
beyes@linux-beyes:~/C/micro> ./mic.exe
hello world


編譯通過,並正常輸出。上面的代碼,在 fprintf() 中的 args 前面加了兩個 # 號 ##。
## 號的作用是
如果可變參數部分( args...) 被忽略或為空,那么 "##" 操作會使預處理器 (preprocessor) 去掉它前面的那個逗號。如果在調用宏時,確實提供了一些可變參數,GNU C 也會正常工作,它會把這些可變參數放在逗號的后面;如果沒有提供,它就會自動去掉前面的逗號,使宏結束展開 ---- 補充完右邊括號。

另外,假如按照 C99 的定義來用,改宏為:

引用
#define debug(format, args...) fprintf(stderr, format, ##__VA_ARGS__)


那么編譯會出錯:

引用
beyes@linux-beyes:~/C/micro> gcc -g mic.c -o mic.exe
mic.c:3:58: warning: __VA_ARGS__ can only appear in the expansion of a C99 variadic macro
mic.c:9:1: error: pasting "," and "__VA_ARGS__" does not give a valid preprocessing token
mic.c: In function ‘main’:
mic.c:9: error: ‘__VA_ARGS__’ undeclared (first use in this function)
mic.c:9: error: (Each undeclared identifier is reported only once
mic.c:9: error: for each function it appears in.)


原因在於,args... 和 ##__VA_ARGS__ 是不匹配的,正確的匹配應該是:

引用
#define debug(format, ...) fprintf(stderr, format, ##__VA_ARGS__)


注意,... 省略號對應的就是 __VA_ARGS__

一般的,定義可變參數宏的一個流行方法,形如:

引用
#define DEBUG(args) (printf("DEBUG: "), printf args)
if(n != 0) DEBUG(("n is %d \n", n));


這個方法的一個缺點是,要記住一對額外的括弧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM