宏定義運算符# ##

宏定義可以包含兩個運算符:#和##。

 

#運算符將一個宏的參數轉換爲字符串字面量。它僅允許出現在帶參數的宏的替換列表中。#運算符有大量的用途,這裏只來討論其中的一種。

假設我們決定在調試過程中使用PRINT_INT宏作爲一個便捷的方法,來輸出一個整型變量或表達式的值。#運算符可以使PRINT_INT爲每個輸出的值添加標籤。下面是改進後的PRINT_INT:

#define PRINT_INT(x) printf(#x " = %d\n", x)

x之前的#運算符通知預處理器根據PRINT_INT的參數創建一個字符串字面量。因此,調用

PRINT_INT(i/j);

會變爲

printf("i/j" " = %d\n", i/j);

在C語言中相鄰的字符串字面量會被合併,因此上邊的語句等價於:

printf("i/j = %d\n", i/j);

 

##運算符可以將兩個記號(例如標識符)“粘”在一起,成爲一個記號。如果其中一個操作數是宏參數,“粘合”會在當形式參數被相應的實際參數替換後發生。考慮下面的宏:

#define MK_ID(n) i##n

當MK_ID被調用時(比如MK_ID(1)),預處理器首先使用自變量(這個例子中是1)替換參數n。接着,預處理器將i和1連接成爲一個記號(i1)。下面的聲明使用MK_ID創建了3個標識符:

int MK_ID(1), MK_ID(2), MK_ID(3);

預處理後聲明變爲:

int i1, i2, i3;

##運算符不屬於預處理器經常使用的特性。實際上,想找到一些使用它的情況是比較困難的。爲了找到一個有實際意義的##的應用,我們來重新思考前面提到過的MAX宏。如我們所見,當MAX的參數有副作用時會無法正常工作。一種解決方法是用MAX宏來寫一個max函數。遺憾的是,往往一個max函數是不夠的。我們可能需要一個實際參數是int值的max函數,還需要參數爲float值的max函數,等等。除了實際參數的類型和返回值的類型之外,這些函數都一樣。因此,這樣定義每一個函數似乎是個很蠢的做法。

解決的辦法是定義一個宏,並使它展開後成爲max函數的定義。宏會有唯一的參數type,它表示形式參數和返回值的類型。這裏還有個問題,如果我們是用宏來創建多個max函數,程序將無法編譯。(C語言不允許在同一文件中出現兩個同名的函數。)爲了解決這個問題,我們是用##運算符爲每個版本的max函數構造不同的名字。下面是宏的顯示形式:

#define GENERIC_MAX (type)         \

type type##_max(type x, type y) \

{                                        \

   return x > y ? x : y;             \

}

請注意宏的定義中是如何將type和_max相連來形成新函數名的。

現在,假如我們需要一個針對float值的max函數。下面是如何使用GENERIC_MAX宏來定義函數:

GENERIC_MAX(float)

預處理器會將這行展開爲下面的代碼:

float float_max(float x, float y) { return x > y ? x : y; }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章