9.10 編譯預處理
編譯預處理也是c語言區別其他高階語言的特點,是指在系統對源程式進行編譯之前,對程式中某些特殊的命令列的處理,預處理程式將根據源**中的預處理命令修改程式,使用預處理功能,可以改善程式的設計環境,提高程式的通用性、可讀性、可修改性、可除錯性、可移植性和方便性,易於模組化。
其處理過程如圖9-11所示。
預處理命令有以下幾個特點:
(1)預處理命令是一種特殊的命令,為了區別一般的語句,必須以#開頭,結尾不加分號。
(2)預處理命令可以放在程式中的任何位置,其有效範圍是從定義開始到檔案結束。
c語言中的預處理命令有巨集定義、檔案包含和條件編譯三類。
預處理命令有以下幾個特點:
(1)預處理命令是一種特殊的命令,為了區別一般的語句,必須以#開頭,結尾不加分號。
(2)預處理命令可以放在程式中的任何位置,其有效範圍是從定義開始到檔案結束。
c語言中的預處理命令有巨集定義、檔案包含和條件編譯三類。
9.10.1 巨集定義
巨集是提供了一種機制,可以用來替換源程式中的字串。從本質上說,就是替換,用一串字串替換程式中指定的識別符號。因此巨集定義也叫巨集替換,巨集替換有兩類:簡單的字元替換和帶引數的巨集替換。
1、字元替換
(1)格式:
#define 識別符號 字串
其中,識別符號稱為巨集名,字串稱為巨集替換體。
(2)功能:編譯之前,預處理程式將程式中該巨集定義之後出現的所有識別符號(巨集名)用指定的字串進行替換。在源程式通過編譯之前,c的編譯程式先呼叫c預處理程式對巨集定義進行檢查,每發現乙個識別符號,就用相應的字串替換,只有在完成了這個過程之後,才將源程式交給編譯系統。
例9-31:預處理。
#define n 10
main( )
編譯該程式之前,預處理程式首先將所有出現的n用10替換。這個過程叫做巨集展開。
(3)使用巨集應當注意的是
①巨集定義僅僅是符號替換,不是賦值語句,因此不做語法檢查。
②為了區別程式中其他的識別符號,巨集名的定義通常用大寫字母。
③雙引號中出現的巨集名不替換。
例如:#define pi 3.14159
printf ("pi=%f", pi);
結果為:pi=3.14159
雙引號中的pi不進行替換。
④如果提前結束巨集名的使用,程式中可以使用#undefine 。
⑤使用巨集定義可以巢狀,即後定義的巨集中可以使用先定義的巨集。
使用巨集可以有以下好處:
(1)在輸入源程式,可以節省許多操作。
(2)巨集經定義之後,可以使用多次,因此使用巨集可以增強程式的易讀性和可靠性。
(3)使用巨集系統不需額外的開銷,因為巨集所代表的**只在巨集出現的地方展開,因此並不會引起程式的跳轉。
2、帶引數的巨集
進行巨集替換時,可以像使用函式一樣,通過實參與形參傳遞資料,增加程式的靈活性。
(1)格式:
#define 識別符號(形參表) 形參表示式
例:#define s(a,b) (a>b)?(a):(b)
(2)功能:預處理程式將程式中出現的所有帶實參的巨集名,展開成由實參組成的表示式。
例9-32:帶引數的巨集替換。
#define s(a,b) (a>b)? (a):(b) /* 定義帶引數的巨集名s */
main( )
(3)說明:
① 巨集名與括號之間不可以有空格。
② 有些引數表示式必須加括號,否則,在實參表示式替換時,會出現錯誤
例:#define s(x) x*x
在程式中,a的值為5,b的值為8,c=s(a+b),替換後的結果為:
c=a+b*a+b
代入a和b的值之後,c=5+8*5+8,值是53,並不是希望的:
c=(a+b)*(a+b)
帶引數的巨集與函式類似,都有形參與實參,有時功能兩者效果是相同的,但二者是不相同的。其主要區別有:
① 函式的形參與實參要求型別一致,而巨集替換不要求型別。
② 函式只有乙個返回值,巨集替換有可能有多個結果。
③ 函式影響執行時間,巨集替換影響編譯時間。
④ 使用巨集有可能給程式帶來意想不到的***。
例9-33:求1到10平方之和。
方法一:使用函式
main( )
fun ( int k )
結果:1,4,9,……,100
方法二:使用巨集
#define fun(a) a*a
main( )
{ int k=1;
while ( k<=10 )
printf ( "%d", fun(k++) );
} 分析:預處理程式將程式中 帶實參的fun替換成(k++)*(k++),由於c語言中,實參的求值順序是從右向左,因此程式執行結果為:
第一次迴圈: (k++)*(k++) 為 2*1
第二次迴圈: (k++)*(k++) 為 4*3
第三次迴圈: (k++)*(k++) 為 6*5
第四次迴圈: (k++)*(k++) 為 8*7
第五次迴圈: (k++)*(k++) 為 10*9
程式執行過程共迴圈5次。
應當盡量避免用自增變數做巨集替換的實參。類似的還有:
#define sum(x) x*x*x
程式中:y=sum(++x);替換的結果即:
y=((++x)*(++x)*(++x))
本文**
編譯預處理
所謂編譯預處理,就是在c源程式的編譯之前,由編譯預處理程式對這些編譯預處理命令進行處理的過程。最常見的就是常量的替換。編譯預處理按功能可以分為巨集定義,檔案包含和條件編譯三類。編譯預處理命令以 開頭,下面進行詳細說明 一.巨集定義與符號常量 1.無參巨集定義 define 識別符號 字串 1 巨集名...
編譯預處理
1.巨集定義指令 1 定義變數與命令 避免幻數 在巨集定義命名時,盡量能清楚的表明功能,大寫 不能以 開頭易與內建巨集衝突 2 定義巨集函式 define max a,b a b a b int num max 6,5 6 5 6 5 用編譯時間換記憶體空間的是巨集函式 用記憶體空間換執行空間的是內...
編譯預處理
1 定義常量與命令 避免幻數 定義巨集時,避免以 開頭,以防與內建巨集定義衝突。巨集和列舉的區別 a.列舉常量是實體常量中的一種,但巨集不是實體 b.列舉常量屬於常量,但巨集不是常量 c.列舉常量具有型別,但巨集沒有型別。列舉型別主要用於限制性輸入,巨集只是預處理替換符 d.列舉只可以表示整型,巨集...