在查看Android的log功能代碼的時(shí)候發(fā)現(xiàn)了如下宏定義:
#define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
參考如下鏈接和C99標(biāo)準(zhǔn)編寫測(cè)試代碼及輸出測(cè)試如下:
鏈接地址:
http://topic.csdn.net/u/20090311/22/dada8228-9254-47da-b88a-4895fd83ddde.html
http://www.vimer.cn/2010/03/cc%E5%AE%8F%E5%AE%9A%E4%B9%89%E7%9A%84%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0.html
http://www.uml.org.cn/c%2B%2B/200902104.asp
http://baike.baidu.com/view/1967819.htm?fr=ala0_1
http://eelab.tsinghua.edu.cn/book/09-11/856891276060145.html
http://blog.csdn.net/chenglian_999/archive/2009/11/04/4765317.aspx
語(yǔ)法解釋:
在最前強(qiáng)調(diào)一點(diǎn),#和##只有在宏定義中有效,其他地方無(wú)效
#(可以稱之為hash字符,the # operator,#運(yùn)算符),它的作用就是將它后面的東西轉(zhuǎn)換成字符串。它的作用可以通過(guò)測(cè)試代碼中的宏定義的#define LOGD部分注釋掉的代碼和未注釋掉的代碼互換來(lái)進(jìn)行理解。(紅色部分)
##的作用是將前后兩部分粘合在一起,例子為
#define HASH_HASH STR(# ## #)
#define HASHTEST ####
//--------notice about the space in #define--------------
#define CONTACT(a, b) STR(a ## b)
#define NOSPACE_CONTACT(a, b) STR(a##b)
#define NEW_CONTACT(a,b) newfun(a HASH_HASH b) //a new token is not ever a ##
#define _NEW_CONTACT(a,b) STR(newfun(a HASH_HASH b))
//-------------------------------------------------
帶參數(shù)的宏定義的測(cè)試也是紅色字體部分,參考資料中解釋為:
"..."代表可變參數(shù)列表, 如果它不是僅有的參數(shù), 那么它只能出現(xiàn)在參數(shù)列表的最后. 調(diào)用這樣的函數(shù)宏時(shí), 傳遞給它的參數(shù)個(gè)數(shù)要不少于參數(shù)列表中參數(shù)的個(gè)數(shù)(多余的參數(shù)被丟棄).
通過(guò)__VA_ARGS__來(lái)替換函數(shù)宏中的可變參數(shù)列表. 注意__VA_ARGS__只能用于函數(shù)宏中參數(shù)中包含有"..."的情況.
測(cè)試代碼:
#include <stdio.h>
#define STR(s) #s
//#define LOGD(...) printf(#__VA_ARGS__)
#define LOGD(...) printf(__VA_ARGS__)
#define HASH_HASH STR(# ## #)
#define HASHTEST ####
//--------notice about the space in #define--------------
#define CONTACT(a, b) STR(a ## b)
#define NOSPACE_CONTACT(a, b) STR(a##b)
#define NEW_CONTACT(a,b) newfun(a HASH_HASH b) //a new token is not ever a ##
#define _NEW_CONTACT(a,b) STR(newfun(a HASH_HASH b))
//-------------------------------------------------
HASHTEST
HASH_HASH
NEW_CONTACT(I,m)
CONTACT(I,m)
NOSPACE_CONTACT(c,d)
//------------------------------------------------
int main()
{
LOGD("This is a test for C99 #define!""/r/n");
LOGD(STR(Test STR defination)"/r/n");
LOGD(HASH_HASH"/r/n");
LOGD(CONTACT(I,m)"/r/n");
LOGD(NOSPACE_CONTACT(c,d)"/r/n");
LOGD(_NEW_CONTACT(I,m)"/r/n");
LOGD(STR(NEW_CONTACT(I,m))"/r/n");
return 0;
}
使用gcc命令:
gcc -E test.c
展開宏定義得到如下代碼:
HASHTEST
"##"
newfun(I "##" m)
"Im"
"cd"
int main()
{
printf("This is a test for C99 #define!""/r/n");
printf("Test STR defination""/r/n");
printf("##""/r/n");
printf("Im""/r/n");
printf("cd""/r/n");
printf("newfun(I HASH_HASH m)""/r/n");
printf("NEW_CONTACT(I,m)""/r/n");
return 0;
}
屏蔽不規(guī)范語(yǔ)法最后編譯執(zhí)行的結(jié)果如下:
This is a test for C99 #define!
Test STR defination
##
Im
cd
newfun(I HASH_HASH m)
NEW_CONTACT(I,m)
一般在調(diào)試打印Debug信息的時(shí)候, 需要可變參數(shù)的宏. 從C99開始可以使編譯器標(biāo)準(zhǔn)支持可變參數(shù)宏(variadic macros), 另外GCC也支持可變參數(shù)宏, 但是兩種在細(xì)節(jié)上可能存在區(qū)別.
1. __VA_ARGS__
__VA_ARGS__ 將 "..." 傳遞給宏 . 如
#define debug(format, ...) fprintf(stderr, format, __VA_ARGS__)
2. GCC的復(fù)雜宏
GCC使用一種不同的語(yǔ)法,從而可以給可變參數(shù)一個(gè)名字,如同其它參數(shù)一樣.
#define debug(format, args...) fprintf (stderr, format, args)
這和第一條的宏例子是完全一樣的,但是這么寫可讀性更強(qiáng)并且更容易進(jìn)行描述.
3. ##__VA_ARGS__
上面兩個(gè)定義的宏,如果出現(xiàn) debug("A Message")的時(shí)候,由于宏展開后有個(gè)多余的逗號(hào),所以將導(dǎo)致編譯錯(cuò)誤.
為了解決這個(gè)問(wèn)題,CPP 使用一個(gè)特殊的"##"操作,格式如下:
#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
這里,如果可變參數(shù)被忽略或?yàn)榭?"##"操作將使預(yù)處理器(preprocessor)去除掉它前面的那個(gè)逗號(hào).