帶引數的巨集定義

2021-07-10 07:30:27 字數 3429 閱讀 7688

不是進行簡單的字串替換,還要進行引數替換。其定義的一般形式為

#define 巨集名(參數列) 字串

字串中包含在括弧中所指定的引數。如:

#define s(a,b) a*b

area=s(3,2);

定義矩形面積s,a 和 b 是邊長。在程式中用了s(3,2),把3、2分別代替巨集定義中的形式引數a、b,即用 3*2 代替 s(3,2)。因此賦值語句展開為

area=3*2;

對帶參的巨集定義是這樣展開轉換的:在程式中如果有帶實參的巨集(如s(3,2)),則按 #define 命令列中指定的字串從左到右進行置換。如果串中包含巨集中的形參(如a、b),則將程式語句中相應的實參(可以是常量、變數或表示式)代替形參。如果巨集定義中的字串中的字元不是引數字元(如 a*b 中的 * 號),則保留。這樣就形成了置換的字串,見右圖。

【例1】

#define pi 3.1415926

#define s(r) pi*r*r

main()

執行結果如下:

r=3.600000

area=40.715038

賦值語句"area=s(a)";經巨集展開後為

area=3.1415926*a*a;

說明:(1) 對帶引數的巨集的展開只是將語句中的巨集名後面括號內的實參字串代替 #define 命令列中的形參。例1中語句中有s(a),在展開時,找到 #define 命令列中的 s(r),將 s(a) 中的實參 a 代替巨集定義中的字串「pi*r*r」中的形參r,得到pi*a*a。這是容易理解而且不會發生什麼問題的。但是,如果有以下語句:

area=s(a+b);

這時把實參 a+b 代替 pi*r*r 中的形參r,成為

area=pi*a+b*a+b;

請注意在 a+b 外面沒有括弧,顯然這與程式設計者的原意不符。原意希望得到

area=pi*(a+b)*(a+b);

為了得到這個結果,應當在定義時,在字串中的形式引數外面加乙個括弧。即

#define s(r) pi*(r)*(r)

在對 s(a+b) 進行巨集展開時,將 a+b 代替 r,就成了

pi*(a+b)*(a+b)

這就達到了目的。

(2) 在巨集定義時,在巨集名與帶引數的括弧之間不應加空格,否則將空格以後的字元都作為替代字串的一部分。例如,如果有

#define s (r) pi*r*r

被認為 s 是符號常量(不帶參的巨集名),它代表字串「(r) pi*r*r」。如果在語句中有

area=s (a);

則被展開為

area=(r) pi*r*r (a);

顯然不對了。

有些讀者容易把帶引數的巨集和函式混淆。的確,它們之間有一定類似之處,在呼叫函式時也是在函式名後的括弧內寫實參,也要求實參與形參的數目相等。但是帶參的巨集定義與函式是不同的。主要有:

(1) 函式呼叫時,先求出實參表示式的值,然後代入形參。而使用帶參的巨集只是進行簡單的字元替換。例如上面的 s(a+b),在巨集展開時並不求 a+b 的值,而只將實參字元「a+b」代替形參r。

(2) 函式呼叫是在程式執行時處理的,為形參分配臨時的記憶體單元。而巨集展開則是在編譯前進行的,在展開時並不分配記憶體單元,不進行值的傳遞處理,也沒有「返回值」的概念。

(3) 對函式中的實參和形參都要定義型別,二者的型別要求一致,如不一致,應進行型別轉換。而巨集不存在型別問題,巨集名無型別,它的引數也無型別,只是乙個符號代表,展開時代入指定的字串即可。巨集定義時,字串可以是任何型別的資料。例如:

#define char1 china  (字元)

#define a 3.6     (數值)

char1 和 a 不需要定義型別,它們不是變數,在程式中凡遇 char1 均以 china 代之;凡遇 a 均以 3.6 代之,顯然不需定義型別。同樣,對帶參的巨集:

#define s(r) pi*r*r

r 也不是變數,如果在語句中有 s(3.6),則展開後為 pi*3.6*3.6,語句中並不出現r。當然也不必定義 r 的型別。

(4) 呼叫函式只可得到乙個返回值,而用巨集可以設法得到幾個結果。

【例2】

#define pi 3.1415926

#define circle(r,l,s,v) l=2*pi*r;s=pi*r*r;v=4.0/3.0*pi*r*r*r

main()

經預編譯巨集展開後的程式如下:

main()

請注意,實參 r 的值已知,可以從巨集帶回3個值(l,s,v)。其實,只不過是字元代替而已,將字元r代替r,l代替l,s代替s,v代替v,而並未在巨集展開時求出l、s、v的值。

(5) 使用巨集次數多時,巨集展開後源程式長,因為每展開一次都使程式增長,而函式呼叫不使源程式變長。

(6) 巨集替換不佔執行時間,只佔編譯時間。而函式呼叫則佔執行時間(分配單元、保留現場、值傳遞、返回)。

一般用巨集來代表簡短一的表示式比較合適。有些問題,用巨集和函式都可以。如:

#define max(x,y) (x)>(y)?(x):(y)

main()

賦值語句展開後為

t=(a+b)>(c+d)?(a+b):(c+d);

注意:max不是函式,這裡只有乙個 main 函式,在 main 函式中就能求出 t 的值。

這個問題也可用函式來求:

int max(int x,int y)

main()

max是函式,在 main 函式中呼叫 max 函式才能求出 t 的值。

請仔細分析以上兩種方法。

如果善於利用巨集定義,可以實現程式的簡化,如事先將程式中的「輸出格式」定義好,以減少在輸出語句中每次都要寫出具體的輸出格式的麻煩。

【例3】

#define pr printf

#define nl "\n"

#define d "%d"

#define d1 d nl

#define d2 d d nl

#define d3 d d d nl

#define d4 d d d d nl

#define s "%s"

main()

執行時輸出以下結果:112

1231234

china

程式中用 pr 代表 printf。以 nl 代表執行一次「換行」操作。以 d 代表輸出乙個整型資料的格式符。以 d1 代表輸出完1個整數後換行,d2 代表輸出2個整數後換行,d3 代表輸出3個整數後換行,d4 代表輸出4個整數後換行。以 s 代表輸出乙個字串的格式符。可以看到,程式中寫輸出語句就比較簡單了,只要根據需要選擇已定義的輸出格式即可,連 printf 都可以簡寫為pr。

可以參照例3,寫出各種輸入輸出的格式(例如實型、長整型、十六進製制整數、八進位制整數、字元型等),把它們單獨編成乙個檔案,它相當乙個「格式庫」,用 #include 命令把它「包括」到自己所編的程式中,使用者就可以根據情況各取所需了。顯然在寫大程式時,這樣做是很方便的。

不帶引數的巨集定義

不帶引數的巨集定義

巨集定義及帶引數的巨集定義

include 巨集定義,通常用於定義常量,在 轉換成二進位制檔案時會將 中的巨集名稱替換成值 define 巨集名稱 值 define a 1 帶引數的巨集 fun a,b 為巨集的名稱 a b為巨集的值 帶引數的巨集比函式效率高 define fun a,b a b 為了保證替換結果,最好加入 ...

不帶引數的巨集定義與帶引數的巨集定義

巨集定義是c提供的三種預處理功能的其中一種,這三種預處理包括 巨集定義 檔案包含 條件編譯 1.不帶引數的巨集定義 巨集定義又稱為巨集代換 巨集替換,簡稱 巨集 格式 define 識別符號 字串其中的識別符號就是所謂的符號常量,也稱為 巨集名 預處理 預編譯 工作也叫做巨集展開 將巨集名替換為字串...

mysql巨集引數 C語言帶引數的巨集定義

c語言允許巨集帶有引數。在巨集定義中的引數稱為 形式引數 在巨集呼叫中的引數稱為 實際引數 這點和函式有些類似。對帶引數的巨集,在展開過程中不僅要進行字串替換,還要用實參去替換形參。帶參巨集定義的一般形式為 define 巨集名 形參列表 字串 在字串中可以含有各個形參。帶參巨集呼叫的一般形式為 巨...