第12章_編譯預處理_第1頁
第12章_編譯預處理_第2頁
第12章_編譯預處理_第3頁
第12章_編譯預處理_第4頁
第12章_編譯預處理_第5頁
已閱讀5頁,還剩26頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、12.1“12.1“文件包含文件包含”處理處理12.2 12.2 宏定義宏定義12.3 12.3 條件編譯條件編譯 基本概念基本概念 ANSI CANSI C標準規(guī)定可以在源程序中加入一些標準規(guī)定可以在源程序中加入一些“預處預處理命令理命令” ,以改進程序設計環(huán)境,提高編程效率。,以改進程序設計環(huán)境,提高編程效率。 這些預處理命令是由這些預處理命令是由ANSI CANSI C統(tǒng)一規(guī)定的,但是它不統(tǒng)一規(guī)定的,但是它不是是C C語言本身的組成部分,不能直接對它們進行編譯語言本身的組成部分,不能直接對它們進行編譯(因為編譯程序不能識別它們)。必須在對程序進(因為編譯程序不能識別它們)。必須在對程序進

2、行通常的編譯之前,先對程序中這些特殊的命令進行通常的編譯之前,先對程序中這些特殊的命令進行行“預處理預處理”。 經(jīng)過預處理后程序可由編譯程序對預處理后的源程經(jīng)過預處理后程序可由編譯程序對預處理后的源程序進行通常的編譯處理,得到可供執(zhí)行的目標代碼序進行通常的編譯處理,得到可供執(zhí)行的目標代碼。 提供的預處理功能主要有以下三種:提供的預處理功能主要有以下三種:文件包含文件包含宏定義宏定義條件編譯條件編譯 這些功能分別用宏定義命令、文件包含命令這些功能分別用宏定義命令、文件包含命令、條件編譯命令來實現(xiàn)。為了與一般語句相區(qū)、條件編譯命令來實現(xiàn)。為了與一般語句相區(qū)別,這些命令以符號別,這些命令以符號“”開

3、頭。例如:開頭。例如: #define #define #include #include 所謂所謂“文件包含文件包含”處理是指一個源文件可以將另外一個處理是指一個源文件可以將另外一個源文件的全部內(nèi)容包含進來。語言提供了源文件的全部內(nèi)容包含進來。語言提供了#include#include命命令用來實現(xiàn)令用來實現(xiàn)“文件包含文件包含”的操作。的操作。其一般形式為: #include 文件名或 #include 12.1 “文件包含文件包含”處理處理注意:注意: 在編譯時并不是分別對主文件和被包含頭文在編譯時并不是分別對主文件和被包含頭文件分別進行編譯,然后再將它們的目標程序件分別進行編譯,然后再將

4、它們的目標程序連接的,連接的,而是在經(jīng)過編譯預處理后將頭文件而是在經(jīng)過編譯預處理后將頭文件包含到主文件中,得到一個新的源程序,然包含到主文件中,得到一個新的源程序,然后對該文件進行編譯后對該文件進行編譯,得到一個目標(,得到一個目標(.obj.obj)文件。被包含的文件成為新的源文件的一)文件。被包含的文件成為新的源文件的一部分,而單獨生成目標文件。部分,而單獨生成目標文件。(1) (1) 一個一個#include#include命令只能指定一個被包含文件,命令只能指定一個被包含文件,如果要包含個文件,要用個如果要包含個文件,要用個#include#include命令。命令。(2) (2) 如

5、果文件包含文件,而在文件中要用到如果文件包含文件,而在文件中要用到文件的內(nèi)容,則可在文件中用兩個文件的內(nèi)容,則可在文件中用兩個includeinclude命令分別包含文件和文件,而且文件應出命令分別包含文件和文件,而且文件應出現(xiàn)在文件之前,即在現(xiàn)在文件之前,即在file1.cfile1.c中定義。中定義。(3) (3) 在一個被包含文件中又可以包含另一個被包含在一個被包含文件中又可以包含另一個被包含文件,即文件包含是可以嵌套的。文件,即文件包含是可以嵌套的。 (4) (4) 在在#include#include命令中,文件名可以用雙撇號或尖括號括命令中,文件名可以用雙撇號或尖括號括起來。二者的

6、區(qū)別是起來。二者的區(qū)別是用尖括弧用尖括弧時,系統(tǒng)將時,系統(tǒng)將在存放在存放C C庫函庫函數(shù)頭文件所存的目錄中數(shù)頭文件所存的目錄中尋找要包含的文件,這稱為標準尋找要包含的文件,這稱為標準方式。用方式。用雙引號時,系統(tǒng)先在用戶當前目錄中尋找要包雙引號時,系統(tǒng)先在用戶當前目錄中尋找要包含的文件,若找不到,再按標準方式查找(即再按尖括含的文件,若找不到,再按標準方式查找(即再按尖括號的方式查找)。號的方式查找)。一般說,如果為調用庫函數(shù)而用一般說,如果為調用庫函數(shù)而用# # includeinclude命令來包含相關的頭文件,則用尖括號,以節(jié)命令來包含相關的頭文件,則用尖括號,以節(jié)省查找時間。如果要包含

7、的是用戶自己編寫的文件(這省查找時間。如果要包含的是用戶自己編寫的文件(這種文件一般都在當前目錄中),一般用雙引號。種文件一般都在當前目錄中),一般用雙引號。 (5) (5) 被包含文件(被包含文件(file2.hfile2.h)與其所在的文件)與其所在的文件(即用(即用#include#include命令的源文件命令的源文件file2.cfile2.c),),在預編譯后已成為同一個文件(而不是兩在預編譯后已成為同一個文件(而不是兩個文件)。因此,如果個文件)。因此,如果file2.hfile2.h中有全局靜中有全局靜態(tài)變量,它也在態(tài)變量,它也在file1.hfile1.h文件中有效,不必文件

8、中有效,不必用用externextern聲明。聲明。 12.2 宏定義宏定義12.2.1 不帶參數(shù)的宏定義不帶參數(shù)的宏定義宏定義一般形式為宏定義一般形式為: :define define 標識符標識符 字符串字符串例如:例如: define PI 3.1415926define PI 3.1415926宏定義的作用是在本程序文件中用指定的標識符宏定義的作用是在本程序文件中用指定的標識符PIPI來代替來代替“3.14159263.1415926”這個字符串,在編譯預處理這個字符串,在編譯預處理時,將程序中在該命令以后出現(xiàn)的所有的時,將程序中在該命令以后出現(xiàn)的所有的PIPI都用都用“3.14159

9、263.1415926”代替。這種方法使用戶能以一個簡代替。這種方法使用戶能以一個簡單的名字代替一個長的字符串。單的名字代替一個長的字符串。這個標識符(名字)稱為這個標識符(名字)稱為“宏名宏名”。在預編譯時將宏名替換成字符串的過程稱為在預編譯時將宏名替換成字符串的過程稱為“宏展宏展開開”。definedefine是宏定義命令是宏定義命令。#include #define PI 3.1415926void main() float l,s,r,v;printf(“input radius : ”);scanf(“%f”,&r);l=2.0*PI*r;s=PI * r * r; v=3.0/4

10、* PI * r * r * r ;printf(“l(fā)=%10.4fns=%10.4fnv=%10.4fn”,l,s,v);return;例例12.1 12.1 使用不帶參數(shù)的宏定義。使用不帶參數(shù)的宏定義。input radius: input radius: 4 運行情況如下:運行情況如下:1=25.13281=25.1328s=50.2655s=50.2655v=150.7966v=150.7966(1) (1) 宏名一般習慣用大寫字母表示,以便與變量名相區(qū)別。宏名一般習慣用大寫字母表示,以便與變量名相區(qū)別。但這并非規(guī)定,也可用小寫字母。但這并非規(guī)定,也可用小寫字母。(2) (2) 使用宏

11、名代替一個字符串,可以減少程序中重復書寫某使用宏名代替一個字符串,可以減少程序中重復書寫某些字符串的工作量。些字符串的工作量。(3) (3) 宏定義是用宏名代替一個字符串,只作簡單置換,不作宏定義是用宏名代替一個字符串,只作簡單置換,不作正確性檢查。只有在編譯已被宏展開后的源程序時才會發(fā)正確性檢查。只有在編譯已被宏展開后的源程序時才會發(fā)現(xiàn)語法錯誤并報錯?,F(xiàn)語法錯誤并報錯。(4) (4) 宏定義不是語句,不必在行末加分號。如果宏定義不是語句,不必在行末加分號。如果加了分號則會連分號一起進行置換。加了分號則會連分號一起進行置換。(5) (5) definedefine命令出現(xiàn)在程序中函數(shù)的外面,宏

12、名命令出現(xiàn)在程序中函數(shù)的外面,宏名的有效范圍為定義命令之后到本源文件結束。通的有效范圍為定義命令之后到本源文件結束。通常,常,definedefine命令寫在文件開頭,函數(shù)之前,作命令寫在文件開頭,函數(shù)之前,作為文件一部分,在此文件范圍內(nèi)有效。為文件一部分,在此文件范圍內(nèi)有效。(6) (6) 可以用可以用unundefdef命令終止宏定義的作用域。命令終止宏定義的作用域。例如:例如: #define G 9.8 #define G 9.8 _void main() void main() G G的有效范圍的有效范圍 -#undef#undef G G f1() f1() 在在f1f1函數(shù)中,不

13、再代表函數(shù)中,不再代表9.89.8。這樣可以靈活控制宏。這樣可以靈活控制宏定義的作用范圍。定義的作用范圍。(7) (7) 在進行宏定義時,可以引用已定義的宏名,可以層層置換在進行宏定義時,可以引用已定義的宏名,可以層層置換。 #include stdio.h#include #define R 3.0#define R 3.0#define PI 3.1415926#define PI 3.1415926#define L 2#define L 2* *PIPI* *R R#define S PI#define S PI* *R R* *R Rvoid main()void main() pr

14、intf(L printf(L=%fnS=%fnS=%fn,L,S);=%fn,L,S); 運行情況如下:運行情況如下:L=18.849556L=18.849556S=28.274333S=28.274333例例12.2 12.2 在宏定義中引用已定義的宏名在宏定義中引用已定義的宏名。經(jīng)過宏展開后,經(jīng)過宏展開后,printfprintf函數(shù)中的輸出項被展開為函數(shù)中的輸出項被展開為: : 2 2* *3.14159263.1415926* *3.03.0展開為展開為 3.14159263.1415926* *3.03.0* *3.03.0printfprintf函數(shù)調用語句展開為函數(shù)調用語句展開

15、為: :printf(“Lprintf(“L=%FNS=%fn”,=%FNS=%fn”,2 2* *3.14159263.1415926* *3.0,3.14159263.0,3.1415926* *3.03.0* *3.0);3.0);(8) (8) 對程序中用雙撇號括起來的字符串內(nèi)的字符,對程序中用雙撇號括起來的字符串內(nèi)的字符,即使與宏名相同,也不進行置換。即使與宏名相同,也不進行置換。 (9) (9) 宏定義是專門用于預處理命令的一個專用名詞宏定義是專門用于預處理命令的一個專用名詞,它與定義變量的含義不同,只作字符替換,不,它與定義變量的含義不同,只作字符替換,不分配內(nèi)存空間。分配內(nèi)存空

16、間。12.2.2 帶參數(shù)的宏定義帶參數(shù)的宏定義 作用:作用:不是進行簡單的字符串替換,還要進行參數(shù)替換。不是進行簡單的字符串替換,還要進行參數(shù)替換。 帶參數(shù)的宏定義一般形式為帶參數(shù)的宏定義一般形式為: :define define 宏名(參數(shù)表)宏名(參數(shù)表) 字符串字符串 字符串中包含在括弧中所指定的參數(shù)字符串中包含在括弧中所指定的參數(shù)#define #define S(a,b) a S(a,b) a* *b b area=S(3,2);area=S(3,2); 程序中用和分別代替宏定義程序中用和分別代替宏定義中的形式參數(shù)和中的形式參數(shù)和b b,用,用* *代代替替S(3,2)S(3,2)

17、。因此賦值語句展開。因此賦值語句展開為:為:area=3area=3* *2 2例:例: 對帶實參的宏對帶實參的宏(如(如S S(3 3,2 2),),則按則按definedefine命令行命令行中指定的字符串從左到右中指定的字符串從左到右進行置換。若串中包含宏進行置換。若串中包含宏中的形參,則將程序中相中的形參,則將程序中相應的實參代替形參。如果應的實參代替形參。如果宏定義中的字符串中的字宏定義中的字符串中的字符不是參數(shù)字符,則保留符不是參數(shù)字符,則保留。這樣就形成了置換的字。這樣就形成了置換的字符串。符串。對帶參的宏定義是這樣展開置換的:對帶參的宏定義是這樣展開置換的: #include

18、stdio.h#include #define PI 3.1415926#define PI 3.1415926#define S(r) PI#define S(r) PI* *r r* *r rvoid main()void main() float a,area; float a,area; a=3.6; a=3.6; area=S(a area=S(a); ); printf(r printf(r=%fnarea=%fnarea=%fn,a,area);=%fn,a,area); 運行情況如下:運行情況如下:=3.600000=3.600000 area=40.715038 area=4

19、0.715038例例12.3 12.3 使用帶參的宏使用帶參的宏賦值語句賦值語句“area=S(a);area=S(a); ” ” 經(jīng)宏展開后為:經(jīng)宏展開后為:area=3.1415926area=3.1415926* * *; (1)(1)對帶參數(shù)的宏展開只是將語句中的宏名后面括對帶參數(shù)的宏展開只是將語句中的宏名后面括號內(nèi)的實參字符串代替號內(nèi)的實參字符串代替definedefine 命令行中的命令行中的形參。形參。(2) (2) 在宏定義時,在宏名與帶參數(shù)的括弧之間不應在宏定義時,在宏名與帶參數(shù)的括弧之間不應加空格,否則將空格以后的字符都作為替代加空格,否則將空格以后的字符都作為替代字符串的

20、一部分。字符串的一部分。 (1) (1) 函數(shù)調用時,先求出實參表達式的值,然后代入形參函數(shù)調用時,先求出實參表達式的值,然后代入形參。而使用帶參的宏只是進行簡單的字符替換。而使用帶參的宏只是進行簡單的字符替換。(2) (2) 函數(shù)調用是在程序運行時處理的,為形參分配臨時的函數(shù)調用是在程序運行時處理的,為形參分配臨時的內(nèi)存單元。而宏展開則是在編譯前進行的,在展開內(nèi)存單元。而宏展開則是在編譯前進行的,在展開時并不分配內(nèi)存單元,不進行值的傳遞處理,也沒時并不分配內(nèi)存單元,不進行值的傳遞處理,也沒有有“返回值返回值”的概念。的概念。(3) (3) 對函數(shù)中的實參和形參類型要求一致。而宏名無類型對函數(shù)

21、中的實參和形參類型要求一致。而宏名無類型,它的參數(shù)也無類型,只是一個符號代表,展開時,它的參數(shù)也無類型,只是一個符號代表,展開時代入指定的字符串即可。宏定義時,字符串可以是代入指定的字符串即可。宏定義時,字符串可以是任何類型的數(shù)據(jù)。任何類型的數(shù)據(jù)。(4) (4) 調用函數(shù)只可得到一個返回值,而用宏可以設法得到調用函數(shù)只可得到一個返回值,而用宏可以設法得到幾個結果。幾個結果。 #include stdio.h#include #define PI 3.1415926#define PI 3.1415926#define CIRCLE(R,L,S,V)#define CIRCLE(R,L,S,V)

22、L=2L=2* *PIPI* *R;S=PIR;S=PI* *R R* *R;V=4.0/3.0R;V=4.0/3.0* *PIPI* *R R* *R R* *R Rvoid main()void main() float r,l,s,v; float r,l,s,v; scanf(%f,&r scanf(%f,&r);); CIRCLE(r,l,s,v CIRCLE(r,l,s,v); ); printf(r printf(r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2fn,=%6.2f,l=%6.2f,s=%6.2f,v=%6.2fn,r,l,s,vr,l,s,v););

23、例例12.4 12.4 通過宏展開得到若干個結果通過宏展開得到若干個結果。void mainvoid main()() float r,l,s,v; float r,l,s,v; scanf(%f,&r scanf(%f,&r);); l=2l=2* *3.14159263.1415926* *r; r; s=3.1515926 s=3.1515926* *r r* *r;r; v=4.0/3/0 v=4.0/3/0* *3.14159263.1415926* *r r* *r r* *r;r; printf(rprintf(r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2fn =

24、%6.2f,l=%6.2f,s=%6.2f,v=%6.2fn ,r,l,s,v);,r,l,s,v);對宏進行預編譯,展開后的對宏進行預編譯,展開后的mainmain函數(shù)如下:函數(shù)如下:運行情況如下:運行情況如下:3.53.5 r r=3.50=3.50,l=21.99l=21.99,s=38.48s=38.48,v=179.59v=179.59(5) (5) 使用宏次數(shù)多時,宏展開后源程序長,因為每展開一次使用宏次數(shù)多時,宏展開后源程序長,因為每展開一次都使程序增長,而函數(shù)調用不會使源程序變長。都使程序增長,而函數(shù)調用不會使源程序變長。(6) (6) 宏替換不占運行時間,只占編譯時間。而函數(shù)

25、調用則占宏替換不占運行時間,只占編譯時間。而函數(shù)調用則占運行時間(分配單元、保留現(xiàn)場、值傳遞、返回)。運行時間(分配單元、保留現(xiàn)場、值傳遞、返回)。 如果善于利用宏定義,可以實現(xiàn)程序的如果善于利用宏定義,可以實現(xiàn)程序的簡化,如事先將程序中的簡化,如事先將程序中的“輸出格式輸出格式”定義定義好,以減少在輸出語句中每次都要寫出具體好,以減少在輸出語句中每次都要寫出具體的輸出格式的麻煩。的輸出格式的麻煩。例例12.5 12.5 通過宏展開得到若干個結果通過宏展開得到若干個結果。#include stdio.h#include #define PR printf#define PR printf#de

26、fine NL n#define NL n#define D %d#define D %d#define D1 D NL#define D1 D NL#define D2 D D NL#define D2 D D NL#define D3 D D D NL#define D3 D D D NL#define D4 D D D D NL#define D4 D D D D NL#define S %s#define S %svoid main()void main() int int a,b,c,d; a,b,c,d; char string=CHINA; char string=CHINA; a=1;b=2;c=3;d=4; a=1;b=2;c=3;d=4;

溫馨提示

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

評論

0/150

提交評論