巨集定義 和 運算子的區別

2021-10-09 17:55:12 字數 1623 閱讀 6365

#運算子將乙個巨集的引數轉換為字串字面量。它僅允許出現在帶引數的巨集的替換列表中。

(一些c程式設計師將#操作理解為「stringization(字串化)」;其他人則認為這實在是對英語的濫用。)

#運算子有大量的用途,這裡只來討論其中的一種。假設我們決定在除錯過程中使用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);

當程式執行時,printf函式會同時顯示表示式i/j和它的值。例如,如果i是11,j是2的話,輸出為

i/j = 5

##運算子##運算子可以將兩個記號(例如識別符號)「粘」在一起,成為乙個記號。(無需驚訝,##運算子被稱為「記號粘合」。)如果其中乙個運算元是巨集引數,「粘合」會在當形式引數被相應的實際引數替換後發生。考慮下面的巨集:

#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) \

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

現在,假如我們需要乙個針對float值的max函式。下面是如何使用generic_max巨集來定義函式:

generic_max(float)

預處理器會將這行展開為下面的**:

float float_max(float x, float y)

巨集定義中的運算子 和

巨集定義可以包含兩個運算子 和 編譯器不會識別這兩種運算子相反,它們會在預處理時被執行。運算子將乙個巨集的引數轉換為字串字面量。它僅允許出現在帶引數的巨集的替換列表中。一些c程式設計師將 操作理解為 stringization 字串化 其他人則認為這實在是對英語的濫用。運算子有大量的用途,這裡只來討...

和 巨集運算子

代表將標記轉換成字串。如 define a token token a hello 就是 hello 注意,這裡也可以跟字串拼接。如 define a token hello token a world 就是 hello world 即 hello world 代表將兩邊標記連線成乙個標記。如 de...

C語言巨集定義中 和 運算子

巨集定義可以包含兩個專用的運算子 和 運算子將巨集的乙個引數轉換為字串字面量,所執行的操作可以理解為 字串化 它僅允許出現在帶引數的巨集的替換列表中。舉個例子 define print int n printf n d n n n之前的 運算子通知預處理器根據print int的引數建立乙個字串字面...