編譯預(yù)處理(最終講稿)_第1頁
編譯預(yù)處理(最終講稿)_第2頁
編譯預(yù)處理(最終講稿)_第3頁
編譯預(yù)處理(最終講稿)_第4頁
編譯預(yù)處理(最終講稿)_第5頁
已閱讀5頁,還剩31頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、第8章 編譯預(yù)處理,河南理工大學(xué),重點(diǎn)、難點(diǎn),本章重點(diǎn): 宏定義命令 條件編譯命令 文件包含命令 本章難點(diǎn): 帶參宏定義 條件編譯,內(nèi)容提要,8.1 宏定義 8.1.1 無參宏定義 8.1.2 帶參宏定義 8.2 條件編譯 8.3 文件包含,所謂編譯預(yù)處理是指,在對源程序進(jìn)行編譯之前,先對源程序中的編譯預(yù)處理命令進(jìn)行處理;然后再將處理的結(jié)果和源程序一起進(jìn)行編譯,得到目標(biāo)代碼。 C語言提供的編譯預(yù)處理命令主要有宏定義、條件編譯和文件包含等三種。為了能夠和一般C語句區(qū)別開來,編譯預(yù)處理命令以“#”號開頭。它占用一個(gè)單獨(dú)的書寫行,命令行末尾沒有分號。,8.1 宏定義,宏定義是指將一個(gè)標(biāo)識符(又稱宏名

2、)定義為一個(gè)字符串(或稱替換文本)。在編譯預(yù)處理時(shí),對程序中出現(xiàn)的所有宏名都用相應(yīng)的替換文本去替換,這稱為“宏替換”或“宏展開”。 在語言中,“宏定義”可分為無參宏定義和帶參宏定義兩種。,8.1.1 無參宏定義,無參宏定義即定義沒有參數(shù)的“宏”,其一般形式為: #define 標(biāo)識符 替換文本 其中#define表示該語句行是宏定義命令,“標(biāo)識符”為所定義的宏名,習(xí)慣上宏名用大寫字母表示;“替換文本”可以是常量、關(guān)鍵字、表達(dá)式、語句等任意字符串。在define、宏名和替換文本之間分別用空格隔開。 #define命令可以不包含“替換文本”,此時(shí)僅說明宏名已被定義,以后可以使用。 第2章介紹的符號

3、常量的定義就是一種無參宏定義。,例8-1 用無參宏定義計(jì)算,s=3*(y*y+3*y)+4*(y*y+3*y)+5*(y*y+3*y) #define M (y*y+3*y) main() int s,y; printf(Please input a number: ); scanf(%d, 運(yùn)行情況如下: Please input a number: 4 s=336,注意,在宏定義中替換文本(y*y+3*y)兩邊的括號不能少,否則會(huì)產(chǎn)生錯(cuò)誤。如改為以下定義: #difine M y*y+3*y 則在宏展開時(shí)將得到下述語句: s=3*y*y+3*y+4*y*y+3*y+5*y*y+3*y; 顯

4、然與原題意要求不符,計(jì)算結(jié)果當(dāng)然是錯(cuò) 的。因此在進(jìn)行宏定義時(shí)必須注意,應(yīng)保證 宏代換之后不發(fā)生錯(cuò)誤。,說明,(1) 習(xí)慣上宏名用大寫字母表示,以便與變量名區(qū)別開。但這并非規(guī)定,也允許使用小寫字母。 (2) 用替換文本替換宏名只是一種簡單的直接替換,替換文本中可以包含任意字符,系統(tǒng)在進(jìn)行編譯預(yù)處理時(shí)對它不作任何檢查。 例如:#define PI 3.l415926 (編譯時(shí)才報(bào)錯(cuò)) (3) 宏定義不是聲明或執(zhí)行語句,在行末不要加分號,如果加上分號則連分號也一起替換。 (4) 一個(gè)#define只能定義個(gè)宏,且一行只能定義一個(gè)宏。若需要定義多個(gè)宏就要使用多個(gè)#define,并寫在多行上。,(5)

5、宏定義時(shí)如果一行寫不下,可用“”續(xù)行。 例如: #define PI 3.1415926 /*正確*/ #define PI 3.1415 926 /*正確*/ (6) 宏定義原則上可以出現(xiàn)在源程序的任何地方,但通常寫在函數(shù)之外,其作用域?yàn)閺暮甓x命令起到源程序文件結(jié)束。如要終止其作用域可使用#undef命令,其用法為: #undef 標(biāo)識符 如:#undef PI,(7) 宏名在源程序中若用雙撇號括起來,則在編譯預(yù)處理時(shí)不對其作宏替換。也就是說,宏名被雙撇號括起來時(shí),僅作為一般字符串使用。 例8-2 宏替換的選擇性。 #define PI 3.1415926 main() printf(PI

6、 is %9.7f.n,PI); 程序運(yùn)行結(jié)果為: PI is 3.1415926.,(8) 宏定義允許嵌套,在宏定義的替換文本中可以使用已經(jīng)定義過的宏名。在宏展開時(shí)層層替換。 例如: #define PI 3.1415926 #define S PI*r*r /* PI是已定義的宏名*/ 對語句: printf(%f,S); 在宏替換后變?yōu)椋?printf(%f,3.1415926*r*r);,例8-3 用無參宏定義表示常用的數(shù)據(jù)類型和輸出格式。,#define INTEGER int #define REAL float #define P printf #define D %dn #de

7、fine F %fn main() INTEGER a=5, c=8, e=11; REAL b=3.8, d=9.7, f=21.08; P(D F,a,b); P(D F,c,d); P(D F,e,f); ,程序運(yùn)行結(jié)果為: 5 3.800000 8 9.700000 11 21.080000,8.1.2 帶參宏定義,帶參宏定義的一般形式為: #define 宏名(形參表) 替換文本 其中,形參表由一個(gè)或多個(gè)形參組成,各形參之間用逗號隔開,替換文本中通常應(yīng)包括有形參。 引用帶參宏的一般形式為: 宏名(實(shí)參表) 帶參宏定義展開時(shí),先把宏引用替換為替換文本,再將替換文本中出現(xiàn)的形參用實(shí)參代替

8、。,例8-4 用帶參宏定義求兩數(shù)中的大者,#define MAX(a,b) (ab)?a:b main() int x,y,max; printf(input two numbers(x,y): ); scanf(%d,%d, 程序運(yùn)行情況如下: input two numbers(x,y): 5,6 max=6,注意!,(1) 在帶參宏定義中,宏名與其后的左括弧“(”之間不得有空格,否則將變?yōu)闊o參宏定義。 例如把: #define MAX(a,b) (ab)?a:b 寫為: #define MAX (a,b) (ab)?a:b 將被認(rèn)為是無參宏定義,宏名是MAX,替換文本為(a,b) (ab

9、)?a:b。 對語句:max=MAX(x,y); 進(jìn)行宏替換后,將變?yōu)椋?max=(a,b) (ab)?a:b(x,y);這顯然是錯(cuò)誤的。,(2)在帶參宏定義中,替換文本中的形參通常要用括號括起來以避免出錯(cuò)。,例8-5 分別引用以下宏定義,求3*F(3+2)的值。 (A) #define F(x) x*x+x (B) #define F(x) (x)*(x)+(x) (C) #define F(x) (x*x+x) (D) #define F(x) (x)*(x)+(x) 解:表達(dá)式3*F(3+2)在分別引用以上4個(gè)宏定義后,其值為: (A) 因?yàn)楹甓x只作為一種簡單的字符替換,所以在引用(A

10、)中的宏定義后,表達(dá)式3*F(3+2)被替換3*3+2*3+2+3+2 (B) 80。表達(dá)式3*F(3+2)被替換為:3*(3+2)*(3+2)+(3+2) (C) 48。表達(dá)式3*F(3+2)被替換為:3*(3+2*3+2+3+2) (D) 90。表達(dá)式3*F(3+2)被替換為 3*(3+2)*(3+2)+(3+2) 由此可見,使用帶參數(shù)的宏定義,替換文本中的括號位置不同,可以得出不同的結(jié)果。使用時(shí)一定要仔細(xì)考慮。,(3) 宏定義也可用來定義多個(gè)語句,在宏替換時(shí),把這些語句都替換到源程序中。,例8-6 一個(gè)宏定義代表多個(gè)語句。 #define SSSV(s1,s2,s3,v) s1=l*w;

11、 s2=l*h; s3=w*h; v=w*l*h; main() int l=3,w=4,h=5,sa,sb,sc,vv; SSSV(sa,sb,sc,vv); printf(sa=%dnsb=%dnsc=%dnvv=%dn,sa,sb,sc,vv); 程序運(yùn)行結(jié)果為: sa=12 sb=15 sc=20 vv=60,帶參宏定義與函數(shù)的主要區(qū)別如下:,(1) 定義方式不同。帶參宏使用預(yù)處理命令#define定義;而函數(shù)使用函數(shù)定義。 (2) 參數(shù)性質(zhì)不同。帶參宏的參數(shù)表中的參數(shù)不必說明其類型,也不分配存儲空間;而函數(shù)參數(shù)表中的參數(shù)需說明其類型并在使用時(shí)為其分配存儲空間。 (3) 實(shí)現(xiàn)方式不同。

12、宏展開是在編譯時(shí)由預(yù)處理程序完成的,不占用運(yùn)行時(shí)間;而函數(shù)調(diào)用是在程序運(yùn)行時(shí)進(jìn)行,需占用一定的運(yùn)行時(shí)間。 (4) 參數(shù)傳遞不同。若實(shí)參為表達(dá)式,引用帶參宏時(shí)只進(jìn)行簡單的字符替換,不計(jì)算實(shí)參表達(dá)式的值;而函數(shù)調(diào)用時(shí),則先計(jì)算表達(dá)式的值,然后代入形參。 (5) 返回值不同。帶參宏定義無返回值;而函數(shù)有返回值。,例8-7 帶參宏定義的實(shí)參是表達(dá)式的情況,#define SQ(y) (y)*(y) main() int a,sq; printf(input a number: ); scanf(%d, 程序運(yùn)行情況如下: input a number: 3 sq=16,“完全展開,直接代替”,例8-8

13、 函數(shù)與帶參宏定義的進(jìn)一步比較,#define SQ_MACRO(y) (y)*(y) main() int i=1; printf(SQ_fun:n); while(i=5) printf(%dn,SQ_fun(i+); i=1; printf(SQ_MACRO:n); while(i=5) printf(%dn,SQ_MACRO(i+); SQ_fun(int y) return(y)*(y); ,程序運(yùn)行結(jié)果為: SQ_fun: 1 4 9 16 25 SQ_MACRO: 2 12 30,8.2 條件編譯,條件編譯是在編譯源文件之前,根據(jù)給定的條件決定編譯的范圍。 一般情況下,源程序中所

14、有語句都參加編譯。但有時(shí)希望在滿足一定條件時(shí),編譯其中的一部分語句,在不滿足條件時(shí)編譯另一部分語句。這就是所謂的“條件編譯”。 條件編譯對于程序的移植和調(diào)試是很有用的。在一套程序要產(chǎn)生不同的版本(如演示版本和實(shí)際版本)、避免重復(fù)定義時(shí)往往使用條件編譯。,條件編譯的三種形式,(1) 第一種形式: #ifdef 標(biāo)識符 程序段1 #else 程序段2 #endif 功能是:如果標(biāo)識符是已被#define命令定義過的宏名,就對程序段1進(jìn)行編譯;否則對程序段2進(jìn)行編譯。,#ifdef 標(biāo)識符 程序段 #endif,例8-9 根據(jù)需要設(shè)置條件編譯,使之能控制對一些提示信息的輸出。,#define DEB

15、UG main() int a=4; #ifdef DEBUG printf(Now the programmer is debugging the program.); #else printf(a=%d.,a); #endif 程序運(yùn)行結(jié)果為: Now the programmer is debugging the program. 若沒有第一行的宏定義命令,程序運(yùn)行后會(huì)輸出: a=4.,(2) 第二種形式: #ifndef 標(biāo)識符 程序段1 #else 程序段2 #endif 功能是:如果標(biāo)識符未被#define命令定義過的宏名,就對程序段1進(jìn)行編譯;否則對程序段2進(jìn)行編譯。,(3) 第

16、三種形式: #if 常量表達(dá)式 程序段1 #else 程序段2 #endif 功能是:如果常量表達(dá)式的值為真(非0),就對程序段1進(jìn)行編譯;否則對程序段2進(jìn)行編譯。,例8-10 設(shè)置一個(gè)開關(guān),判斷輸入值是半徑還是邊長,實(shí)現(xiàn)求圓或正方形的面積。,#define R 1 main() float c,r,s; printf (input a number:); scanf(%f, #endif ,程序運(yùn)行情況如下: input a number:3 area of round is: 28.274309 若程序的第一行改為: #define R 0 則程序運(yùn)行情況如下: input a numbe

17、r:3 area of square is: 9.000000,8.3 文件包含,所謂文件包含是指在一個(gè)文件中包含另一個(gè)文件的全部內(nèi)容,使之成為該文件的一部分。這相當(dāng)于是兩個(gè)文件的合并。文件包含由文件包含命令#include來實(shí)現(xiàn),其一般格式為: #include /*格式一*/ 或 #include 文件名 /*格式二*/ 其中“文件名”是指被包含的文件,稱為頭文件。頭文件必須是文本文件,如C語言源程序文件等。頭文件常以“.h”為后綴(h為head的縮寫),但也可以是“.c”或其他,甚至沒有后綴也是可以的。,區(qū)別,格式一和格式二的主要區(qū)別是在存放頭文件的路徑上。 使用格式一時(shí),預(yù)處理程序只在

18、系統(tǒng)規(guī)定的目錄(include子目錄)中去查找指定的頭文件,若找不到,則出錯(cuò),這稱為標(biāo)準(zhǔn)方式。 使用格式二時(shí),預(yù)處理程序先在當(dāng)前工作目錄中尋找指定的頭文件,若找不到,再按標(biāo)準(zhǔn)方式去查找。,區(qū)別,一般來說,如果調(diào)用系統(tǒng)提供的標(biāo)準(zhǔn)庫函數(shù)時(shí)使用格式一(庫函數(shù)相關(guān)的頭文件一般放在系統(tǒng)規(guī)定的目錄),以節(jié)省查找時(shí)間。 如果要包含的是用戶自己編寫的頭文件(這種頭文件往往放在當(dāng)前工作目錄),則一般使用格式二。,區(qū)別,另外,格式一中只能寫文件名及其后綴,不能含有其他成分,但格式二中的雙撇號內(nèi)可以含有路徑,如: #include /*錯(cuò)誤*/ #include C:TCF2.c /*正確*/,優(yōu)點(diǎn),使用文件包含的手段,可以減少重復(fù)性的勞動(dòng),有利于程序的維護(hù)和修改,同時(shí)也是“模塊化”設(shè)計(jì)思想所要求的。 將那些公用的或常用的宏定義、函數(shù)原型、數(shù)據(jù)類型定義及全局變量的定義和聲明等,組織在一些頭文件中,在程序需要使用到這些信息時(shí),就用#include命令把它們包含到所需的位置上去,從而免去每次使用它們時(shí)都要重新定義或聲明的麻煩。,例8-11 用戶頭文件的編寫和使用,L8_11.h文件源代碼如下: #ifndef _L8_11_H #define _L8_11_H /*定義宏,以防止重復(fù)包含此頭文件*/ #include #define ADD(

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論