C語言程序設(shè)計(jì)基礎(chǔ)與應(yīng)用 第8章_第1頁
C語言程序設(shè)計(jì)基礎(chǔ)與應(yīng)用 第8章_第2頁
C語言程序設(shè)計(jì)基礎(chǔ)與應(yīng)用 第8章_第3頁
C語言程序設(shè)計(jì)基礎(chǔ)與應(yīng)用 第8章_第4頁
C語言程序設(shè)計(jì)基礎(chǔ)與應(yīng)用 第8章_第5頁
已閱讀5頁,還剩53頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、第8章 預(yù)處理8.1 概述8.2 宏定義8.3 文件包含8.4 條件編譯8.5 運(yùn)行一個(gè)多文件的程序8.6 常見錯(cuò)誤分析8.7 小結(jié)習(xí)題實(shí)驗(yàn)與實(shí)訓(xùn)在前面各章中,我們已多次使用過以符號(hào)“#”開頭的預(yù)處理命令。例如包含命令#include,宏定義命令#define等。在源程序中,這些命令都放在函數(shù)之外,且一般是放在源文件的前面,它們被稱為預(yù)處理部分。預(yù)處理是語言的一個(gè)重要功能,它由預(yù)處理程序負(fù)責(zé)完成。所謂編譯預(yù)處理,是指在對(duì)源程序進(jìn)行編譯之前,先對(duì)源程序中的編譯預(yù)處理命令進(jìn)行處理;然后再將處理的結(jié)果與源程序一起進(jìn)行編譯,得到目標(biāo)代碼。8.1 概述語言提供了多種預(yù)處理功能,例如宏定義、文件包含、條件

2、編譯等。合理地使用預(yù)處理功能編寫的程序便于閱讀、修改、移植和調(diào)試,也有利于模塊化程序設(shè)計(jì)。本章將介紹常用的幾種預(yù)處理功能。在語言源程序中允許用一個(gè)標(biāo)識(shí)符來表示一個(gè)字符串,稱為“宏”。被定義為宏的標(biāo)識(shí)符稱為“宏名”。在編譯預(yù)處理時(shí),對(duì)程序中所有出現(xiàn)的宏名,都用宏定義中的字符串去替換,被稱為“宏代換”或“宏展開”。8.2 宏定義使用宏定義可以提高源程序的可維護(hù)性、可移植性,以及減少源程序中重復(fù)書寫字符串的工作量。宏定義是由源程序中的宏定義命令完成的。宏替換是由預(yù)處理程序自動(dòng)完成的。在語言中,宏分為帶參數(shù)宏和無參數(shù)宏兩種。下面分別討論這兩種宏的定義和調(diào)用。1. 定義宏名后不帶參數(shù)的宏為無參數(shù)宏。無參

3、數(shù)宏定義的一般形式為#define 宏名 字符串其含義是將在程序中出現(xiàn)“宏名”的地方均用“字符串”來替代。前面使用過的符號(hào)常量的定義就是一種無參數(shù)宏定義。例如,#define N 10。又例如, #define M (y*y + 3*y),該宏定義表示在程序中出現(xiàn)M的地方均用表達(dá)式(y*y + 3*y)替代。8.2.1 無參數(shù)宏例題8.1 格式化輸入/輸出。#define FORMAT %f,%f,%f,%fmain() floatx1, x2, x3, x4; printf(Please enter 4 float numbers:); scanf(FORMAT, &x1, &x2, &x3

4、, &x4); printf(n); printf(FORMAT, x1, x2, x3, x4);說明 本例題中兩次用到格式控制符%f,%f,%f,%f。通過使用宏,簡(jiǎn)化了源程序,同時(shí)又不易出錯(cuò)。例題8.2 宏定義的正確使用。#define M (y*y + 3*y)main() int result, y; printf(Input a number: ); scanf(%d, &y); result= 3*M + 4*M + 5*M; printf(Result=%dn, result);說明 上例程序中要注意的是,在宏定義中表達(dá)式(y*y + 3*y)兩邊的括號(hào)不能少,否則會(huì)發(fā)生錯(cuò)誤。

5、2. 使用宏應(yīng)注意的問題(1) 宏定義不是說明或語句,在行末不必加分號(hào),如果加上分號(hào)則會(huì)連分號(hào)也一起被置換。(2) 宏替換的作用范圍是定義它的源文件。(3) 宏名通常使用大寫字母表示。(4) 宏定義必須寫在函數(shù)之外,其作用域?yàn)樽院甓x命令起到源程序結(jié)束。如果要終止其作用域,可以使用#undef命令。例如:#define PI 3.14159main() .#undef PIf1() .這里,PI只在main() 有效,在f1函數(shù)中無效。(5) 宏名在源程序中若用引號(hào)括起來,則預(yù)處理程序不對(duì)其作宏替換。例如:#define OK 100main() printf(OK); printf(n);雖

6、然定義宏名OK表示100,但在printf語句中OK被引號(hào)括起來,因此不作宏替換。語言允許宏帶有參數(shù)。在宏定義中的參數(shù)稱為形式參數(shù),在宏調(diào)用中的參數(shù)稱為實(shí)際參數(shù)。對(duì)帶參數(shù)的宏,在調(diào)用中不僅要宏展開,而且要用實(shí)參去替換形參。帶參數(shù)宏的定義形式一般為: #define 宏名(形參表) 字符串,其含義是作相應(yīng)的參數(shù)替換。帶參數(shù)宏調(diào)用的一般形式為: 宏名(實(shí)參表);8.2.2 帶參數(shù)宏例題8.3 帶參數(shù)宏的使用。#define MAX(a, b) (a b) ? abmain() int num_1,num_2, max; printf(Input two numbers: ); scanf(%d%d

7、, & num_1, &num_2); max = MAX(num_1,num_2); printf(Max=%dn, max);說明 上例程序的第1行進(jìn)行帶參數(shù)宏定義,第7行max=MAX(num_1,num_2)為宏調(diào)用,實(shí)參num_1,num_2將分別替換形參a,b。注意(1) 帶參數(shù)宏定義中,宏名和形參表之間不能有空格。例如,本例中的宏如果寫為#define MAX (a,b) (ab) ? ab,將被認(rèn)為是無參數(shù)宏定義,宏名MAX代表字符串 (a,b) (ab)?a:b。(2) 定義中的形參是標(biāo)識(shí)符,而宏調(diào)用中的實(shí)參可以是表達(dá)式。例如:#define T(y) (y)*(y) /*

8、形參y是標(biāo)識(shí)符 */main() int num, result; printf(Input a number: ); scanf(%d, &num); result = T(num + 1); /* 實(shí)參num + 1是表達(dá)式 */ printf(result=%dn, result);(3)函數(shù)調(diào)用與帶參數(shù)宏的異同 相似點(diǎn)函數(shù)調(diào)用與宏調(diào)用均在其名稱(函數(shù)名、宏名)后的括號(hào)內(nèi)列出實(shí)參;要求實(shí)參與形參的數(shù)目相等。 不同點(diǎn)函數(shù)調(diào)用時(shí),要把實(shí)參表達(dá)式的值計(jì)算出來再賦予形參;而宏替換中對(duì)實(shí)參表達(dá)式不作計(jì)算,直接照原樣進(jìn)行替換即可。函數(shù)調(diào)用是在程序運(yùn)行時(shí)處理的,分配臨時(shí)的內(nèi)存單元。宏替換是在編譯時(shí)進(jìn)行

9、的,在展開時(shí)并不分配內(nèi)存單元,不進(jìn)行值的傳遞處理。函數(shù)中的實(shí)參與形參均要定義類型,并要求類型一致;宏不存在類型問題,宏名無類型,其參數(shù)也無類型,宏定義時(shí),字符串可以是任何類型的數(shù)據(jù)。函數(shù)調(diào)用只能得到一個(gè)返回值,而宏調(diào)用可得到多個(gè)結(jié)果。例題8.4 函數(shù)調(diào)用與宏調(diào)用的比較。程序段1#define PI 3.1415926main() float r, girth, area; float cir1(float); float cir2(float); printf(Please enter radius: ); scanf(%f, &r); girth = cir1(r); area = cir2

10、(r); printf(girth=%.2f,area=%.2fn, girth, area);float cir1(float y) /* 函數(shù)調(diào)用 */ return(2*PI*y);float cir2(float y) /* 函數(shù)調(diào)用 */ return (PI * y * y);程序段2#define PI 3.1415926#define CRI(r, girth, area) girth = 2*PI*r; area = PI*r*rmain() float r, girth, area; printf(Please enter radius: ); scanf(%f, &r);

11、 CRI(r, girth, area); /* 宏調(diào)用 */ printf(girth=%.2f, area=%.2fn, girth, area);說明 從以上兩個(gè)代碼段可見,要想通過函數(shù)調(diào)用獲得兩個(gè)值周長(zhǎng)和面積,就必須使用兩個(gè)函數(shù)調(diào)用,因?yàn)楹瘮?shù)調(diào)用只能得到一個(gè)返回值。而宏調(diào)用則不同,它可得到多個(gè)值。例題8.5 下面的程序展示了宏的嵌套定義和替換。#include stdio.h#define PI (3.1415926536)#define FUN(k) (k)*PI#define PR(value) printf(Valuefn,(value) main() float area; a

12、rea PI*6.8*6.8; PR(area); PR(FUN(2)*6.8);說明 本例使用了宏的嵌套定義,在宏展開時(shí)由預(yù)處理程序?qū)訉犹鎿Q。文件包含是C預(yù)處理程序的另一個(gè)重要功能。文件包含命令行的一般形式和示例如下:格式 #include 文件名或#include 示例 #include stdio.h #include math.h #include 8.3 文件包含文件包含命令的功能是把指定的文件與當(dāng)前的源程序文件連成一個(gè)源文件。在程序設(shè)計(jì)中,文件包含是非常有用的。一個(gè)大的程序可以分為多個(gè)模塊,由多個(gè)程序員分別編程。有些公用的符號(hào)常量或宏定義等可以單獨(dú)組成一個(gè)文件,在其他文件的開頭用包

13、含命令包含該文件即可使用。這樣,就可以避免在每個(gè)文件開頭都去書寫那些公用量,從而節(jié)省時(shí)間、減少差錯(cuò)。對(duì)文件包含命令的說明如下:(1) 包含命令中的文件名可以用雙引號(hào)括起來,也可以用尖括號(hào)括起來。例如,以下寫法都是允許的: #include “stdio.h”或#include 。但是,這兩種形式是有區(qū)別的。(2) 一個(gè)include命令只能指定一個(gè)被包含文件,若有多個(gè)文件要包含,則需要使用多個(gè)include命令。(3) 文件包含允許嵌套,即在一個(gè)被包含的文件中又可以包含另一個(gè)文件??梢杂?include指令包含擴(kuò)展名不是.h的文件嗎?我們可以用#include命令包含任何一個(gè)文件。如果一個(gè)程序

14、是由多個(gè)源程序文件構(gòu)成的,就可以在一個(gè)源程序文件中使用#include命令把其他程序文件都包含進(jìn)來,這是解決多文件程序的一種有效的方法。當(dāng)然,為了程序的可讀性考慮,最好不要把擴(kuò)展名不是.h的文件用#include命令包含進(jìn)來,這樣不容易區(qū)分哪些文件是用于編譯預(yù)處理的。預(yù)處理程序提供了條件編譯的功能。按不同的條件可以編譯不同的程序部分,因而產(chǎn)生不同的目標(biāo)代碼文件。條件編譯有3種形式,以下分別介紹。8.4 條件編譯1. 第一種形式#ifdef 標(biāo)識(shí)符程序段1 #else 程序段2 #endif 其功能是,如果標(biāo)識(shí)符已被 #define命令定義過,則對(duì)程序段1進(jìn)行編譯;否則,對(duì)程序段2進(jìn)行編譯。例題

15、8.6 條件編譯使用之一。#define Ready 1main() #ifdef Ready printf(Yes!n); #else printf(No!n); #endif2. 第二種形式#ifndef 標(biāo)識(shí)符 程序段1 #else 程序段2 #endif 其功能是,如果標(biāo)識(shí)符未被#define命令定義過,則對(duì)程序段1進(jìn)行編譯;否則,對(duì)程序段2進(jìn)行編譯。這與第一種形式的功能正相反。例題8.7 條件編譯使用之二。#define Headmain() #ifndef Head printf(Error!n); #else printf(Ok!n); #endif3. 第三種形式#if 常量表

16、達(dá)式程序段1 #else 程序段2 #endif其功能是,如果常量表達(dá)式的值為真(非0),則對(duì)程序段1進(jìn)行編譯;否則,對(duì)程序段2進(jìn)行編譯。因此可以使程序在不同條件下完成不同的功能。例題8.8 條件編譯使用之三。#define R 1#define PI 3.1416main() float r, cir_are, squ_are; printf(Input a number: ); scanf(%f, &r); #if R cir_are= PI*r*r; printf(Area of round is: %fn,cir_are); #else squ_are= r*r; printf(Are

17、a of square is: %fn, squ_are); #endif上面介紹的條件編譯當(dāng)然也可以用條件語句來實(shí)現(xiàn)。但是,用條件語句將會(huì)對(duì)整個(gè)源程序進(jìn)行編譯,生成的目標(biāo)代碼程序很長(zhǎng);而采用條件編譯,則會(huì)根據(jù)條件只編譯其中的程序段1或程序段2,生成的目標(biāo)程序較短。如果條件選擇的程序段很長(zhǎng),采用條件編譯的方法是十分必要的。在第7章中,我們利用外部函數(shù)實(shí)現(xiàn)了將多個(gè)C語言模塊組合成一個(gè)程序,本章我們將利用編譯指令,分模塊設(shè)計(jì)來完成這個(gè)工作。下面仍以第7章的例題7.8為例,對(duì)其進(jìn)行改寫。8.5 運(yùn)行一個(gè)多文件的程序例題8.9 多文件程序的運(yùn)行。(1)首先將F11.C,F(xiàn)2_1.C和F2_2.C分別輸

18、入計(jì)算機(jī),編譯后存盤,例如放在D盤的ex目錄下。F2_1.C /* 定義一個(gè)fun1()函數(shù) */extern int num;void fun1(int x) num = num + x; printf(After fun1, num = %dn, num);F2_2.C /* 定義一個(gè)fun2()函數(shù) */extern num;void fun2(char c) num = num + c - 0; printf(After fun2, num = %dn, num);F11.C /* 定義main()主函數(shù) */#include int num;main() printf(Please

19、enter a number: ); scanf(%d, &num); fun1(10); fun2(A);(2)在同一目錄下編寫兩個(gè)頭文件。f21.h /* 定義fun1()函數(shù)的頭文件 */#ifndef _F21_H void fun1(int x);#endif f22.h /* 定義fun2()函數(shù)的頭文件 */#ifndef _F22_H void fun2(char c);#endif(3)在文件F11.C的命令行中加入上述兩個(gè)頭文件,即#include d:exf21.h#include d:exf22.h這樣,在編譯時(shí),系統(tǒng)自動(dòng)將這2個(gè)文件包含到main()函數(shù)的前頭,作為一

20、個(gè)整體編譯,而不是分3個(gè)文件編譯。這時(shí),這些函數(shù)會(huì)被認(rèn)為是在同一個(gè)文件中,不再作為外部函數(shù)被其他文件調(diào)用。main()函數(shù)中的extern聲明可以不要了。(4)選擇File菜單的New命令,在同一目錄下建立一個(gè)新的文件,即項(xiàng)目文件,取名為f.prj,其內(nèi)容只有3行,然后存盤。d:exF11.Cd:exF2_1.Cd:exF2_2.C必要時(shí),還應(yīng)在文件名前加上盤符和路徑,例如本例中是放在D盤的ex目錄下。(5)在Project菜單下添加項(xiàng)目文件d:exf.prj,按功能鍵F9進(jìn)行編譯連接;按Ctrl+F9鍵運(yùn)行。(6)Alt+F5觀察結(jié)果。問題1 文件包含指令中缺少符號(hào)“#”。在宏定義中缺少符號(hào)

21、“#”,如include,這時(shí)編譯會(huì)產(chǎn)生錯(cuò)誤 Declaration Syntax Error。問題2 文件包含指令中多添加了分號(hào)。在宏定義指令的末尾添加了分號(hào),例如“include;”是不符合語法規(guī)定的。8.6 常見錯(cuò)誤分析問題3 文件包含指令中錯(cuò)誤地使用了尖括號(hào)。當(dāng)我們自己編寫了頭文件后需要在文件中包含時(shí),例如例題8.9中的頭文件d:exf21.h,若以尖括號(hào)方式包含即#include,系統(tǒng)就會(huì)到存放C庫函數(shù)頭文件所在的目錄中尋找此文件,這樣就會(huì)出現(xiàn)錯(cuò)誤。因此,對(duì)自己編寫的頭文件應(yīng)使用雙引號(hào),即 #included:exf21.h。問題4 在宏命令中錯(cuò)誤地使用了等號(hào)。在使用define命令

22、時(shí)錯(cuò)誤地使用了等號(hào),例如#define PI = 3.1416。正確的寫法是#define PI 3.1416。問題5 在頭文件中定義變量。前面我們談到一個(gè)變量可以被說明多次,但只能被定義一次。因此,不應(yīng)該在頭文件中定義一個(gè)變量。因?yàn)椋粋€(gè)頭文件可能會(huì)被一個(gè)程序的多個(gè)源文件包含,這樣就會(huì)被反復(fù)定義。預(yù)處理功能是語言特有的功能,它是在對(duì)源程序正式編譯前由預(yù)處理程序完成的。程序員在程序中用預(yù)處理命令來調(diào)用這些功能。使用預(yù)處理功能便于程序的修改、閱讀、移植和調(diào)試,也便于實(shí)現(xiàn)模塊化程序設(shè)計(jì)。預(yù)處理功能包括宏定義、文件包含和條件編譯。宏定義是用一個(gè)標(biāo)識(shí)符來表示一個(gè)字符串,這個(gè)字符串可以是常量、變量或表達(dá)

23、式。在宏調(diào)用中將用該字符串替換宏名。8.7 小結(jié)宏定義可以帶有參數(shù),宏調(diào)用時(shí)是以實(shí)參替換形參,而不是“值傳遞”。為了避免宏替換時(shí)發(fā)生錯(cuò)誤,宏定義中的字符串應(yīng)加上括號(hào),字符串中出現(xiàn)的形式參數(shù)兩邊也應(yīng)添加括號(hào)。文件包含是預(yù)處理的一個(gè)重要功能,它可用來把多個(gè)源文件連接成一個(gè)源文件進(jìn)行編譯,結(jié)果將生成一個(gè)目標(biāo)文件。條件編譯允許只編譯源程序中滿足條件的程序段,使生成的目標(biāo)程序較短,從而減少了內(nèi)存的開銷,提高了程序的效率。8-1 寫出下列各程序段的運(yùn)行結(jié)果。(1) #include #define X 5#define Y X + 1#define Z Y * X / 2main() int a; a =

24、 Y; printf(%d%dn, Z,-a);習(xí)題(2) #include #define TRUE 1#define FALSE 0#define SQ(x) (x)*(x)main() int num; int again = 1; printf(program will stop if input value less 50.n); while(again) printf(please enter number: ); scanf(%d, &num); printf(The square for this number is %dn, SQ(num); if(num = 50) aga

25、in = TRUE;else again = FALSE; (3) #include #define LAG #define SMA #define EQ =main() int i= 10, j = 20; if(i LAG j) printf(%d larger than %dn, i, j); else if(i EQ j) printf(%d equal to %dn, i, j); else if(i SMA j) printf(%d smaller than %dn, i, j); else printf(No such value.n);(4) #include #define

26、MAX#define MAXI(x,y) (xy) ? xy#define MINI(x,y) (xy) ? y xmain() int a = 10, b = 20; #ifdef MAXprintf(40: The larger one is %dn, MAXI(a, b); #elseprintf(40: The lower one is %dn, MINI(a, b); #endif #ifndef MINprintf(40: The lower one is %dn, MINI(a, b); #elseprintf(40: The larger one is %dn, MAXI(a, b); #endif #undef MAX #ifdef MAXprintf(40: The larger one is %dn, MAXI(a, b); #elseprintf(40: The lower one is %dn, MINI(a, b); #endif #define MIN #ifndef MINprintf(40: The lower one is %dn, MINI(a, b); #elseprintf(40: The larger one is %dn, MAXI

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論