c(和c++)中的巨集(macro)屬於編譯器預處理的範疇,屬於編譯期概念(而非執行期概念)。下面對常遇到的巨集的使用問題做了簡單總結。
關於#和##
#define warn_if(exp) /
do /
while(0)
那麼實際使用中會出現下面所示的替換過程:
warn_if (divider == 0);
被替換為
do while(0);
這樣每次divider(除數)為0的時候便會在標準錯誤流上輸出乙個提示資訊。
而##被稱為連線符(concatenator),用來將兩個token連線為乙個token。注意這裡連線的物件是token就行,而不一定是巨集的變數。比如你要做乙個選單項命令名和函式指標組成的結構體的陣列,並且希望在函式名和選單項命令名之間有直觀的、名字上的關係。那麼下面的**就非常實用:
struct command
char * name;
void (*function) (void);
#define command(name)
// 然後你就用一些預先定義好的命令來方便的初始化乙個command結構的陣列了:
struct command commands = {
command(quit),
command(help),
command巨集在這裡充當乙個**生成器的作用,這樣可以在一定程度上減少**密度,間接地也可以減少不留心所造成的錯誤。我們還可以n個##符號連線 n+1個token,這個特性也是#符號所不具備的。比如:
#define link_multiple(a,b,c,d) a##_##b##_##c##_##d
typedef struct _record_type link_multiple(name,company,position,salary);
// 這裡這個語句將展開為:
// typedef struct _record_type name_company_position_salary;
關於...的使用
...在c巨集中稱為variadic macro,也就是變參巨集。比如:
#define myprintf(templt,...) fprintf(stderr,templt,__va_args__)
// 或者
#define myprintf(templt,args...) fprintf(stderr,templt,args)
第乙個巨集中由於沒有對變參起名,我們用預設的巨集__va_args__來替代它。第二個巨集中,我們顯式地命名變參為args,那麼我們在巨集定義中就可以用args來代指變參了。同c語言的stdcall一樣,變參必須作為參數列的最有一項出現。當上面的巨集中我們只能提供第乙個引數templt時,c標準要求我們必須寫成:
myprintf(templt,);
的形式。這時的替換過程為:
myprintf("error!/n",);
替換為:
fprintf(stderr,"error!/n",);
這是乙個語法錯誤,不能正常編譯。這個問題一般有兩個解決方法。首先,gnu cpp提供的解決方法允許上面的巨集呼叫寫成:
myprintf(templt);
而它將會被通過替換變成:
fprintf(stderr,"error!/n",);
很明顯,這裡仍然會產生編譯錯誤(非本例的某些情況下不會產生編譯錯誤)。除了這種方式外,c99和gnu cpp都支援下面的巨集定義方式:
#define myprintf(templt, ...) fprintf(stderr,templt, ##__var_args__)
這時,##這個連線符號充當的作用就是當__var_args__為空的時候,消除前面的那個逗號。那麼此時的翻譯過程如下:
myprintf(templt);
被轉化為:
fprintf(stderr,templt);
這樣如果templt合法,將不會產生編譯錯誤。 這裡列出了一些巨集使用中容易出錯的地方,以及合適的使用方式。
c語言裡的巨集(翻譯)4
巨集引數 function like巨集可以帶引數,就好像函式帶引數一樣。定乙個乙個帶引數巨集的時候,把引數插入到兩個括號之間,就好像定義函式的引數一樣。這就是該類巨集被稱為function like巨集的原因。巨集引數必須是合法的c標識,由逗號和空格隔開。呼叫帶引數的巨集,你可以在寫完巨集名之後插...
c語言裡的巨集(翻譯)2
object like 巨集 object like巨集是乙個簡單的標識,在編譯器會被一段 代替。由於它看上去很像乙個在 中被使用的資料域,所以管它叫object like巨集。最常使用該型別巨集的場合是 用乙個指定符號代替乙個數字常量。使用 define 指令定義乙個巨集,define之後跟乙個巨...
C語言巨集中 和 的用法
c語言巨集中 和 的用法 一 一般用法 我們使用 把巨集引數變為乙個字串,用 把兩個巨集引數貼合在一起.用法 include include using namespace std define str s s define cons a,b int a e b int main printf st...