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

下載本文檔

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

文檔簡介

1、第第9章章 編譯預處理編譯預處理 第第9章章 編譯預處理編譯預處理 9.1 宏定義宏定義 9.2 文件包含文件包含 9.3 條件編譯條件編譯 習題習題9 第第9章章 編譯預處理編譯預處理 9.1 宏定義宏定義 9.1.1 無參數(shù)的宏定義 無參數(shù)宏的宏名后不帶參數(shù)。其定義的一般格式為 #define 宏名 字符串 其中的“#”表示這是一條預處理命令。凡是以“#”開 頭的均為預處理命令。“define”為宏定義命令。“宏名” 為所定義的宏名?!白址笨梢允浅?shù)、表達式和格式 串等。在前面介紹過的符號常量的定義就是一種無參宏定 義。此外,常對程序中反復使用的表達式進行宏定義。 第第9章章 編譯預處

2、理編譯預處理 1. 無參數(shù)宏定義符號常量 符號常量用無參數(shù)的宏定義語句定義,把符號 常量名定義為指定的字符串,將程序中出現(xiàn)宏名的地 方均用該字符串來替換。在進行編譯預處理時,用該 字符串替代程序中出現(xiàn)的符號常量名。例如: #define TRUE 1 #define FALSE 0 把TRUE定義為1,把FALSE定義為0。在符號常量 定義之后,就可以用它來編碼了。 第第9章章 編譯預處理編譯預處理 例如: if(i=TRUE) printf(you are right! n) ; else if(i=FALSE) printf(you are wrong! n) ; 對于該程序段,在進行編譯

3、預處理時,就把程序 中出現(xiàn)的TRUE和FALSE分別用1和0替代,于是就變?yōu)?if(i=1) printf(you are right! n) ; else if(i=0) printf(you are wrong! n) ; 第第9章章 編譯預處理編譯預處理 在符號常量定義語句中,字符串可以是一個數(shù)值型數(shù) 據(jù)、表達式或字符串。例如: #define PI 3.1415926 #define S (PI*r*r) #define PRT printf #define A (20-(3*4) 如果字符串是一個運算表達式,一般應該用括號括 住它,以便把它視為一個操作對象與其他操作數(shù)進行運算, 否則

4、,會由于操作優(yōu)先級問題而發(fā)生錯誤。例如: text = A*8 ; 進行編譯預處理后,該表達式變?yōu)?text = (20-(3*4)*8 ; 第第9章章 編譯預處理編譯預處理 如果A定義為 #define A 20- (3*4) 則表達式text = A*8經預編譯后變?yōu)?text = 20- (3*4)*8 ; 這就不符合原意。因此,在宏定義語句中的字符 串為一般表達式(而不是一個操作數(shù))時,為了保證正確 的運算次序,應該用括號括住它。因此在宏定義時必 須十分注意,應保證在宏代換之后不發(fā)生錯誤。 第第9章章 編譯預處理編譯預處理 2. 無參數(shù)宏的好處 在程序設計中,使用無參數(shù)的宏有下面兩點好

5、處: 1) 增強程序的可讀性 以符號常量為例,由于符號常量含義明確,于是采用 符號常量書寫的程序要比不采用符號常量的可讀性強。例 如: #define LENGTH 20 #define WIDTH 40 #define HEIGTH 60 在程序中用LENGTH、WIDTH、HEIGTH時,一看就 知道它們分別代表長、寬、高,而如果直接用20、40、60, 則很難猜出它們是長、寬、高。 第第9章章 編譯預處理編譯預處理 2) 增強程序的可維護性 如果一個常量在程序中多次被引用,則可把它定義為 符號常量。這樣,在以后需改動該常量時,只需改動它的宏 定義語句即可,而不必對每一個引用它的地方進行修

6、改。這 不但可以減少修改的工作量,而且可以避免漏改。 3. 無參數(shù)宏的注意事項 使用無參數(shù)宏定義符號常量時,一般應注意以下幾點。 (1) 宏定義是用宏名來表示一個字符串,在宏展開時又 以該字符串取代宏名,這只是一種簡單的代換,字符串中可 以含任何字符,可以是常數(shù),也可以是表達式,預處理程序 對它不作任何檢查。如有錯誤,則只能在編譯已被宏展開后 的源程序時發(fā)現(xiàn)。 第第9章章 編譯預處理編譯預處理 (2) 符號常量名一般用大寫字母(也可以用小寫字母)表 示,以便與其他標識符相區(qū)別。符號常量名的命名規(guī)則與 一般標識符相同。另外,應考慮在字符串中根據(jù)需要加上 括號。 (3) 宏定義不是說明或語句,因此

7、,不能用分號結尾。 如果加上分號,則分號被作為字符串的一部分,連分號也 一起置換。例如: #define A 60 ; 上面的格式表示A被定義為“60 ;”,而不是“60”。于 是,在預編譯時,程序中凡是出現(xiàn)A的地方,都用“60 ;” 替換。這就不符合原意了。 (4) 替換字符串可以為空。 第第9章章 編譯預處理編譯預處理 (5) 宏定義語句應放在函數(shù)定義之外,符號常量的 有效范圍是從定義它的宏定義語句開始至所在源文件 的結尾。一般宏定義語句都放在源文件的開頭,以便 使它對整個源文件都有效。 (6) 為了靈活控制宏定義的作用范圍,可用“ undef”命令終止宏定義的作用域。 第第9章章 編譯預

8、處理編譯預處理 例如: #define PI 3.14159 main( ) # undef PI /* PI的宏定義結束 */ f1( ) 表示PI只在main函數(shù)中有效,在f1中無效。 第第9章章 編譯預處理編譯預處理 (7) 宏定義允許嵌套,在宏定義的字符串中可以使用已經 定義的宏名。在宏展開時由預處理程序層層代換。例如: #define PI 3.14 #define R 10 #define S PI*R*R main( ) printf(S=%f , S); 預編譯后,該程序變?yōu)?main( ) printf(S=%f , 3.14*10*10); 第第9章章 編譯預處理編譯預處理

9、 (8) 宏名在源程序中若用引號括起來,則預處理程序不 對其作宏代換。例如: #define NO 220 main( ) printf(NO); printf(n); 上例中定義宏名NO表示220,但在printf語句中NO被引 號括起來,因此不作宏代換。程序的運行結果為 NO 表示把“NO”當字符串處理。 第第9章章 編譯預處理編譯預處理 【例9-1】假設血壓正常值低壓為70,高壓為120。 如果低壓高于70,并且高壓低于120,則為正常。從鍵 盤輸入血壓值,判斷該血壓值是否正常。 #include main( ) #define LOW 70 /* 定義宏 */ #define HIGH

10、 120 /* 定義宏 */ 第第9章章 編譯預處理編譯預處理 int bloodplow , bloodphigh ; do scanf(%d%d , while(bloodplow=bloodphigh) ; if(bloodplowLOW else printf(you may have something wrong!) ; 輸入:130 80 輸出:you may have something wrong! 第第9章章 編譯預處理編譯預處理 【例9-2】已知一梯形的上下兩邊的長分別為a、b,輸 入高h,求其面積。 #include main( ) #define a 5/* 定義宏

11、*/ #define b 15/* 定義宏 */ #define L (a+b)/* 嵌套定義宏 */ 第第9章章 編譯預處理編譯預處理 float h , s ; scanf(%f , s=h*L/2 ; printf(s=%f n , s) ; 輸入:3 輸出:s=30.000000 第第9章章 編譯預處理編譯預處理 【例9-3】利用迭代法求方程的根。其迭代公式為 yi+1=(yi+x/yi)/2。 #include stdio.h main( ) #define ABS 1e-4 float y1 , y , x ; printf(x=) ; scanf(%f , printf(y=)

12、; scanf(%f , do 第第9章章 編譯預處理編譯預處理 y1=y ; y=(y1+x/y1)/2 ; while(y1-y)ABS) ; printf(%fn , y) ; 運行結果: x=2 y=3 1.414214 第第9章章 編譯預處理編譯預處理 9.1.2 帶參數(shù)的宏定義 1. 帶參數(shù)的宏的定義 利用#define語句不僅可以定義符號常量,也可以定義 帶參數(shù)的宏。帶參數(shù)的宏的一般定義格式為 #define 宏名(參數(shù)表) 字符串 字符串中包含參數(shù)表中的參數(shù)。 調用帶參數(shù)宏的一般格式為 宏名(實參表); 例如: #define MIN(a,b) (a)(b)? (a) : (b

13、) 第第9章章 編譯預處理編譯預處理 其中,MIN(a,b)是帶參數(shù)的宏,a和b是形式參數(shù)。 該定義把MIN(a,b)定義為“(a)(b)? (a):(b)”。在定義 了該宏后,就可在程序中用MIN(a,b)替代定義它的運 算表達式“(a)(b)? (a):(b)”。宏的使用方法類似函 數(shù)。例如,在需要求兩個數(shù)的最小值時,就可以使用 已定義的宏。 c= MIN(10,20) ; 在進行編譯時,預編譯程序根據(jù)宏定義式來替換 程序中出現(xiàn)的帶參數(shù)的宏,其中定義式中的形式參數(shù) 用相應的實際參數(shù)替換。于是,上面的賦值語句變?yōu)?c= MIN(10=0)? (x): -(x) /* 求x的絕對值 */ #d

14、efine MAX(a,b) (a)b)?a:b 改寫為 #define MAX(a,b) (ab)?a:b 將被認為是無參宏定義,宏名MAX代表字符串 “(a,b) (ab)?a:b”。宏展開時,宏調用語句: max=MAX(x,y); 將變?yōu)?max=(a,b)(ab)?a:b(x,y); 這顯然是錯誤的。 第第9章章 編譯預處理編譯預處理 【例9-4】鍵盤輸入立方體的邊長a,求其表面積s 及體積v。 #include main( ) #define L(a,s,v) s=6*a*a ; v=a*a*a int a1,s1,v1; a1=0 ; scanf(%d, L(a1,s1,v1)

15、; printf(%d , %d , %dn , a1 , s1 , v1) ; 第第9章章 編譯預處理編譯預處理 【例9-5】求1100所有奇數(shù)的和。 #include main( ) #define ISODD(x) (x)%2=1)? 1:0) int sum , i ; sum=1 ; for(i=3 ; i=100 ; i+) if ISODD(i) sum+=i ; printf(%dn , sum) ; 第第9章章 編譯預處理編譯預處理 【例9-6】已知某單位上繳個人所得稅的算法如下: 輸入工資,求其應上繳的稅款。 #include main( ) #define TAX1(a)

16、 (a=800) ? 0 : (a1300)? 0.05 : (a=2800) ? 0.1 : (a=5800) ? 0.15 : 0.2) #define TAX2(b) (b=1300) ? 0 : (b=2800)? 25 : (b=5800)? 125 : 375) #define TAX3(c) c*TAX1(c)-TAX2(c) 第第9章章 編譯預處理編譯預處理 float tax , wage ; scanf(%f , tax=TAX3(wage) ; printf(%f , %fn , wage , tax) ; 第第9章章 編譯預處理編譯預處理 【例9-7】輸入4個整數(shù),按由

17、小到大的順序輸出。 #include main( ) #define CHANGE(a,b) int t ; t=a; a=b; b=t ; int i , j , k , l ; printf(please input four number:) ; scanf(%d , %d , %d , %d , 第第9章章 編譯預處理編譯預處理 if(ij) CHANGE(i , j) ; if(ik) CHANGE (i , k) ; if(il) CHANGE (i , l) ; if(jk) CHANGE (j , k) ; if(jl) CHANGE (j , l) ; if(kl) CHAN

18、GE (k , l) ; printf(the proper order is:) ; printf(%d %d %d %dn , i , j , k , l) ; 第第9章章 編譯預處理編譯預處理 9.2 文件包含文件包含 在前面章節(jié)中,我們經常在編寫程序中,會寫上 下面的語句: #include 其含義是在編譯時,用stdio.h頭文件的內容替換該 語句。 文件包含語句的一般格式為 #include 文件名 或 #include 第第9章章 編譯預處理編譯預處理 其中,是被包含文件的文件名,它是一個磁盤 文件。該預編譯語句的功能是要將 所指文件的全部內容包含在該#include語句所 在的

19、源文件中。也就是說,在預編譯時,用所指 文件的全部內容替換該#include語句行,使該文件成為這個 源文件的一部分。 在#include語句的書寫格式中,被包含文件的文件名可 用尖括號()括住,也可以用雙引號( )括住。 當用尖括號括住時,表示編譯系統(tǒng)按系統(tǒng)設定的標準目 錄搜索文件;當用雙引號括住時,表示按指定的路徑搜索。 若未指定路徑名時,則在當前目錄中搜索。 第第9章章 編譯預處理編譯預處理 文件包含語句是很有用的語句,特別是對包括多個源 文件的大程序來說,可以把各個源文件中共同使用的函數(shù) 說明、符號常量定義、外部量說明、宏定義和結構類型定 義等寫成一個獨立的包含文件,在需要這些說明的源

20、文件 中,只需在源文件的開頭用一個#include語句把該文件包括 進來,這樣就可以避免重復工作。例如: /* file1.c */ #include file2.h main( ) /*file2.h*/ #define PI 3.14159 第第9章章 編譯預處理編譯預處理 做成包含文件的另一個好處是,當這些常量、宏定義 等需要修改時,只需修改這個被包含的文件即可,而不必 修改各源文件。 使用#include語句時,應注意以下兩點: (1) 一個include命令只能指定一個被包含文件,若有 多個文件要包含,則需用多個include命令。 (2) 文件包含允許嵌套,即在一個被包含的文件中又

21、可 以包含另一個文件。 第第9章章 編譯預處理編譯預處理 9.3 條件編譯條件編譯 一般情況下,源程序中所有的行都參加編譯,但 有時在寫程序時要求根據(jù)具體情況編譯不同的程序代 碼,C語言中提供了條件編譯,可以按不同的條件去編 譯不同的程序部分,因而產生不同的目標代碼文件。 這對于程序的移植和調試是很有用的。條件編譯有3種 形式,下面分別介紹。 第第9章章 編譯預處理編譯預處理 1. #ifdef #else #endif語句 用# ifdef # else # endif語句進行條件編譯的指令 格式為 #ifdef 標識符 程序段1 #else 程序段2 #endif 其作用是:如果標識符已被

22、定義(用#define定義),則對 程序段1進行編譯,而程序段2被刪除;否則,程序段1被刪 除,編譯程序段2。其中,#else部分是可以缺省的,即 第第9章章 編譯預處理編譯預處理 #ifdef 標識符 程序段1 #endif 條件編譯語句中的#ifdef和#endif決定了編譯范圍, 在此范圍外的源程序不存在條件編譯問題。條件編譯 對于提高程序的移植性很有幫助。 第第9章章 編譯預處理編譯預處理 【例9-8】條件編譯#ifdef的使用。 #include stdio.h #define TED 10 main ( ) #ifdef TED printf(Hi Tedn); /* 如果定義了T

23、ED,則編譯此行代碼 */ #else printf(Hi anyonen); /* 如果沒用定義TED,則編譯此行代碼 */ 第第9章章 編譯預處理編譯預處理 printf(Hi anyonen); /* 如果沒用定義TED,則編譯此行代碼 */ #endif #ifndef RALPH printf (RALPH not definedn); /* 如果定義了RALPH,則編譯此行代碼 */ #endif 上述代碼打印“Hi Ted”及“RALPH not defined”。如 果TED沒有定義,則顯示“Hi anyone”,后面是“RALPH not defined”??梢韵袂短?if

24、那樣將#ifdef 與# ifndef 嵌套至 任意深度。 第第9章章 編譯預處理編譯預處理 2. #ifndef #else #endif語句 由#ifndef #else #endif語句進行條件編譯的指令格式 為 #ifndef 標識符 程序段1 #else 程序段2 #endif 與第一種形式的區(qū)別是將“ifdef”改為“ifndef”。它的功 能是:如果標識符未被#define命令定義,則對程序段1進行 編譯,否則對程序段2進行編譯。這與第一種形式的功能正 相反。例如: 第第9章章 編譯預處理編譯預處理 #ifndef UNPRN printf(Name= %s sa= %f, na

25、me , s) ; #else printf(%s %f , name , s) ; #endif 當UNPRN在程序段之前未定義時,則只編譯 “printf(Name= %s sa= %f, name , s) ;”。如果在該程 序段之前加一行: #define UNPRN 1 則只編譯“printf(%s %f , name , s) ;”。其中, UNPRN可定義為任何字符串。 第第9章章 編譯預處理編譯預處理 3. #if #else #endif語句 由#if # else # endif語句進行條件編譯的指令格式為 #if 表達式 程序段1 #else 程序段2 #endif 其作

26、用是:當表達式的值為非0時,編譯程序段1,不編 譯程序段2;否則編譯程序段2(其中#else部分是可以缺省的)。 例如,在程序設計的測試階段,經常要顯示一些變量的信息, 以檢查是否正確,而在正式執(zhí)行時,卻不需要顯示這些信息。 這時,就可以用下面形式的條件編譯。 第第9章章 編譯預處理編譯預處理 #define DEBUG 1 #if DEBUG printf(a=%d b=%f c=%s , a , b , c) ; #endif 以上形式的條件編譯適用測試階段,如果程序測 試完成,在編譯正式的執(zhí)行代碼時,只需把DEBUG定 義為0即可。在進行條件編譯時,可根據(jù)情況選擇條件 編譯語句。 第第9章章 編譯預處理編譯預處理 【例9-9】條件編譯#if的使用。 #include stdio.h #define R 1 main( ) float c,r,s; printf (input a number: ); scanf(%f, #if R 第第9章章 編譯預處理編譯預處理 r=3.14159*c*c; /* 如果R非0,則編譯此行和下一行代碼 */ printf(area of round is: %fn,r); #else s=c*c; /* 如果R為0,則編譯此行和下一行代碼 */ printf(area of square is: %fn,s); #endi

溫馨提示

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

評論

0/150

提交評論