C語言編程常見問題解答之編譯預(yù)處理

字號:

本章集中討論與預(yù)處理程序有關(guān)的問題。在編譯程序?qū)Τ绦蜻M行通常的編譯之前,要先運行預(yù)處理程序。可能你以前沒有見過這個程序,因為它通常在幕后運行,程序員是看不見它的,然而,這個程序非常有用。
     預(yù)處理程序?qū)⒏鶕?jù)源代碼中的預(yù)處理指令來修改你的程序。預(yù)處理指令(如#define)為預(yù)處理程序提供特定的指令,告訴它應(yīng)該如何修改你的源代碼。預(yù)處理程序讀入所有包含的文件和待編譯的源代碼,經(jīng)過處理生成源代碼的預(yù)處理版本。在該版本中,宏和常量標(biāo)識符已用相應(yīng)的代碼和值代替。如果源代碼中包含條件預(yù)處理指令(如#if),預(yù)處理程序?qū)⑾扰袛鄺l件,然后相應(yīng)地修改源代碼。
     預(yù)處理程序有許多非常有用的功能,例如宏定義,條件編譯,在源代碼中插入預(yù)定義的環(huán)境變量,打開或關(guān)閉某個編譯選項,等等。對專業(yè)程序員來說,深入了解預(yù)處理程序的各種特征,是創(chuàng)建快速和高效的程序的關(guān)鍵之一。
     在閱讀本章時,請記住本章采用的一些技術(shù)(以及所提到的一些常見陷阱),以便更好地利用預(yù)處理程序的各種功能。
     5.1 什么是宏(macro)?怎樣使用宏?
     宏是一種預(yù)處理指令,它提供了一種機制,可以用來替換源代碼中的字符串,宏是用“#define"語句定義的,下面是一個宏定義的例子:
     #define VERSION—STAMP "1.02"
     上例中所定義的這種形式的宏通常被稱為標(biāo)識符。在上例中,標(biāo)識符VERSION_STAMP即代表字符串"1.02"——在編譯預(yù)處理時,源代碼中的每個VERSION_STAMP標(biāo)識符都將被字符串“1.02”替換掉。
     以下是另一個宏定義的例子:
     #define CUBE(x)((x),(x)*(x))
     上例中定義了一個名為CUBE的宏,它有一個參數(shù)x。CUBE宏有自己的宏體,即((x)*(x)*(x))——在編譯預(yù)處理時,源代碼中的每個CUBE(x)宏都將被((x)*(x)*(x))替換掉。
     使用宏有以下幾點好處;
     (1)在輸入源代碼時,可省去許多鍵入操作。
     (2)因為宏只需定義一次,但可以多次使用,所以使用宏能增強程序的易讀性和可靠性。
     (3)使用宏不需要額外的開銷,因為宏所代表的代碼只在宏出現(xiàn)的地方展開,因此不會引起程序中的跳轉(zhuǎn)。
     (4)宏的參數(shù)對類型不敏感,因此你不必考慮將何種數(shù)據(jù)類型傳遞給宏。
     需要注意的是,在宏名和括起參數(shù)的括號之間絕對不能有空格。此外,為了避免在翻譯宏時產(chǎn)生歧義,宏體也應(yīng)該用括號括起來。例如,象下例中這樣定義CUBE宏是不正確的:
    denne CUBE(x) x * x * x
     對傳遞給宏的參數(shù)也要小心,例如,一種常見的錯誤就是將自增變量傳遞給宏,請看下例:
    #include
    #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被作為參數(shù)傳遞給宏時進行了自增運算,所以上例中的CUBE宏實際上是按以下形式展開的:
     y = ((++x) * (++x) * (++x));
     這樣,每次引用x時,x都要自增,所以你得到的結(jié)果與你預(yù)期的結(jié)果相差很遠,在上例中,由于x被引用了3次,而且又使用了自增運算符,因此,在展開宏的代碼時,x實際上為8,你將得到8的立方,而不5的立方。
     上述錯誤是比較常見的,作者曾親眼見過有多年C語言編程經(jīng)驗的人犯這種錯誤。因為在程序中檢查這種錯誤是非常費勁的,所以你要給予充分的注意。你試一下上面的例子,親眼看一下那個令人驚訝的結(jié)果值(512)。
     宏也可使用一些特殊的運算符,例如字符串化運算符“#”和。連接運算符“##”。“#”運算符能將宏的參數(shù)轉(zhuǎn)換為帶雙引號的字符串,請看下例:
     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"。這個例子說明,宏所使用的“#”運算符是一種非常方便的調(diào)試工具。
     “##”運算符的作用是將兩個獨立的字符串連接成一個字符串,詳見5.16。