宏是一種預處理指令,它提供了一種機制,可以用來替換源代碼中的字符串,宏是用“#define"語句定義的,下面是一個宏定義的例子:
#define VERSION—STAMP "1.02"
上例中所定義的這種形式的宏通常被稱為標識符。在上例中,標識符VERSION_STAMP即代表字符串"1.02"——在編譯預處理時,源代碼中的每個VERSION_STAMP標識符都將被字符串“1.02”替換掉。
以下是另一個宏定義的例子:
#define CUBE(x)((x),(x)*(x))
上例中定義了一個名為CUBE的宏,它有一個參數x。CUBE宏有自己的宏體,即((x)*(x)*(x))——在編譯預處理時,源代碼中的每個CUBE(x)宏都將被((x)*(x)*(x))替換掉。
使用宏有以下幾點好處:
(1)在輸入源代碼時,可省去許多鍵入操作。
(2)因為宏只需定義一次,但可以多次使用,所以使用宏能增強程序的易讀性和可靠性。
(3)使用宏不需要額外的開銷,因為宏所代表的代碼只在宏出現的地方展開,因此不會引起程序中的跳轉。
(4)宏的參數對類型不敏感,因此你不必考慮將何種數據類型傳遞給宏。
需要注意的是,在宏名和括起參數的括號之間絕對不能有空格。此外,為了避免在翻譯宏時產生歧義,宏體也應該用括號括起來。例如,象下例中這樣定義CUBE宏是不正確的:
denne CUBE(x) x * x * x
對傳遞給宏的參數也要小心,例如,一種常見的錯誤就是將自增變量傳遞給宏,請看下例:
#include <stdio. h>
#include CUBE(x) (x * x * x)
void main (void);
void main (void)
{
int x, y;
x = 5;
y = CUBE( + +x);
printfC'y is %d\n" . y);
}
在上例中,y究竟等於多少呢?實際上,y既不等於125(5的立方),也不等於336(6* 7*8),而是等於512。因為變量x被作為參數傳遞給宏時進行了自增運算,所以上例中的CUBE宏實際上是按以下形式展開的:
y = ((++x) * (++x) * (++x));
這樣,每次引用x時,x都要自增,所以你得到的結果與你預期的結果相差很遠,在上例中,由於x被引用了3次,而且又使用了自增運算符,因此,在展開宏的代碼時,x實際上為8,你將得到8的立方,而不5的立方。
上述錯誤是比較常見的,作者曾親眼見過有多年C語言編程經驗的人犯這種錯誤。因為在程序中檢查這種錯誤是非常費勁的,所以你要給予充分的注意。你最好試一下上面的例子,親眼看一下那個令人驚訝的結果值(512)。
宏也可使用一些特殊的運算符,例如字符串化運算符“#”和。連接運算符“##”。“#”運算符能將宏的參數轉換為帶雙引號的字符串,請看下例:
define DEBUG_VALUE(v) printf(#v"is equal to %d.\n",v)
你可以在程序中用DEBUG_VALUE宏檢查變量的值,請看下例:
int x=20;
DEBUG_VALUE(x);
上述語句將在屏幕上打印"x is equal to 20"。這個例子說明,宏所使用的“#”運算符是一種非常方便的調試工具。
“##”運算符的作用是將兩個獨立的字符串連接成一個字符串。