重修第7章編譯預(yù)處理_第1頁
重修第7章編譯預(yù)處理_第2頁
重修第7章編譯預(yù)處理_第3頁
重修第7章編譯預(yù)處理_第4頁
重修第7章編譯預(yù)處理_第5頁
已閱讀5頁,還剩32頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第7章編譯預(yù)處理本章要求:掌握無參數(shù)宏和帶有參數(shù)宏定義和使用方法;掌握文件包含的使用方法;掌握條件編譯的使用。本章重點(diǎn):無參數(shù)宏和帶有參數(shù)宏定義和使用方法本章難點(diǎn):帶有參數(shù)宏定義和使用方法第7章編譯預(yù)處理在C語言源程序中以“#”號開頭的預(yù)處理命令都放在函數(shù)之外,一般都放在源文件的前面,它們稱為預(yù)處理部分。所謂預(yù)處理是指在進(jìn)行編譯的第一遍掃描(詞法掃描和語法分析)之前所作的工作。預(yù)處理是C語言的一個重要功能,由預(yù)處理程序負(fù)責(zé)完成。對源文件進(jìn)行編譯時,系統(tǒng)將自動引用預(yù)處理程序?qū)υ闯绦蛑蓄A(yù)處理部分作處理,處理完再自動進(jìn)入對源程序的編譯。C語言提供了多種預(yù)處理功能,主要有宏定義、文件包含、條件編譯。第7章編譯預(yù)處理27.1

宏定義#defineC語言源程序中用一個標(biāo)識符來表示一個字符串,稱為宏。被定義為“宏”的標(biāo)識符稱為“宏名”。在編譯預(yù)處理時,對程序中所有出現(xiàn)的“宏名”,都用宏定義中的字符串去代換,稱為“宏代換”或“宏展開”。宏定義是由源程序中的宏定義命令完成的。

宏代換是由預(yù)處理程序自動完成的。

C語言中,“宏”分為有參數(shù)和無參數(shù)兩種。第7章編譯預(yù)處理37.1

宏定義#define7.1.1

無參宏定義一般形式:#define標(biāo)識符字符串作用是用一個指定的標(biāo)識符來代表一個字符串。常使用宏定義命令#define

定義符號常量,若有如下定義:#define

PI

3.1415926535用標(biāo)識符(稱為“宏名”)PI來代表字符串

“3.1415926535”。在編譯預(yù)處理中,即以3.1415926535代替源程序中出現(xiàn)的PI(這個過程稱為“宏展開”)。如程序中的s=PI*r*r等效于s=3.1415926535*r*r。第7章編譯預(yù)處理4第7章編譯預(yù)處理5說明:(1)標(biāo)識符(宏名)命名,遵守C語言標(biāo)識符的命名規(guī)則。為便于與一般變量區(qū)別,宏名常采用大寫字母。(2)宏定義允許嵌套,在宏定義的字符串中可以使用已經(jīng)定義的宏名。在宏展開時由預(yù)處理程序?qū)訉哟鷵Q。如例6-1中有定義: #define

PI

3.1415926#define

S

PI*r*r /*

PI是已定義的宏名*/在編譯預(yù)處理時,語句printf(“The

Area=%lf\n”,S);經(jīng)

printf("TheArea=%lf\n",3.1415926*r*r);注意:若替換的字符串中含有其它字符(如上題中的r),一般要在引用宏的程序需要定義,否則編譯時會出現(xiàn)標(biāo)識符(變量)未定義的錯誤。7.1

宏定義#define第7章編譯預(yù)處理6#definePI=3.1415926535/*

多了等號*/#definePI3.1415926535;/*

多了分號*/(3)宏定義是用宏名代表字符串,僅作簡單置換,不分配內(nèi)存空間,編譯預(yù)處理時不檢查語法。只有在源程序被宏展開后,進(jìn)行編譯時才作語法檢查。下列的宏定義都不可取:上述宏定義對于同一個語句:

s=PI*r*r;宏展開后分別為:

s==3.1415926535*r*r;s=3.1415926535;*r*r;顯然有語法錯誤!7.1

宏定義#define(4)宏替換只對單獨(dú)的宏名單詞進(jìn)行,對于括在引號中的字符串不起作用。若有宏定義:#define

MAX

500對于下列語句:int

MAXICOAT=10; /*

MAX不是獨(dú)立單詞,不替換*/printf(“MAX=”,MAX);/*前面的MAX在引號中,不替換;后面的要替換*/(5)宏定義必須寫在函數(shù)之外,宏名的有效范圍為定義命令之后到該源文件結(jié)束,也可以使用#undef命令來提前終止宏名的作用域。#define

MAX

500┇#undef

MAX┇宏名MAX的有效范圍宏名MAX在此處無效7.1

宏定義#define第7章編譯預(yù)處理7第7章編譯預(yù)處理8(2)宏定義時,宏名與參數(shù)表間不能有空格,否則將作為無參數(shù)宏來處理。如:#define

MAX

(x,y)

x>y?x:y

則認(rèn)為MAX為宏名,而(x,y)x>y?x:y為替代字符串,則易產(chǎn)生錯誤。(3)帶參數(shù)的宏和函數(shù)有相似之處,都有形參實(shí)參的概念,并要求形參實(shí)參數(shù)目相同,一一對應(yīng)。但兩者實(shí)現(xiàn)的過程是不同的。在帶參宏定義中,形式參數(shù)不分配內(nèi)存單元,因此不必

作類型定義。而宏調(diào)用中的實(shí)參有具體的值。要用它們?nèi)ゴ?/p>

換形參,因此必須作類型說明。這是與函數(shù)中的情況不同的。在函數(shù)中,形參和實(shí)參是兩個不同的量,各有自己的作用域,調(diào)用時要把實(shí)參值賦予形參,進(jìn)行“值傳遞”。而在帶參宏

中,只是符號代換,不存在值傳遞的問題。7.1

宏定義#define有效地利用宏定義可以簡化程序,如對輸出格式的宏定義。程序的運(yùn)行結(jié)果為:第7章編譯預(yù)處理95

4.3000005

8

4.300000

2.710800Youare

good!#define

PR

printf#define

NL

"\n"#define

D

"%d

"#define

F

"%f

"#define

S

"%s

"void

main(){

inta=5,b=8;float

x=4.3,y=2.7108;char

ch[]="You

are

good!";PR(DF

NL,a,x); /*printf("%d

%f

"\n",

a,x);

*/PR(D

D

F

FNL,a,b,x,y);PR(S

NL,ch);}7.1

宏定義#define第7章編譯預(yù)處理107.1.2

有參宏定義C語言允許宏帶有參數(shù)。在宏定義中的參數(shù)稱為形式參數(shù),在宏調(diào)用中的參數(shù)稱為實(shí)際參數(shù)。對帶參數(shù)的宏,在調(diào)用中,不僅要宏展開,而且要用實(shí)參去代換形參。帶參宏定義的一般形式為:#define

宏名(形參表)

字符串帶參宏調(diào)用的一般形式為:

宏名(實(shí)參表);宏定義:#define

MAX(x,y)

x>y?x:y宏調(diào)用:z=

MAX(3,4);宏展開:z=3>4?3:4;7.1

宏定義#define例.

用定義帶參數(shù)宏來寫程序,輸入一個圓的半徑,輸出圓的面積。定義帶參數(shù)的宏S(r)。#define

PI

3.1415926535#define

S(r)

PI*r*rvoid

main(){float

a,

area;a

=

5;area=S(a);

/*宏展開為area=3.1415926535*a*a;*/printf("r=%f\narea=%f\n",a,area);}這樣可以解決,無參數(shù)宏定義中,替換字符串中含有其他字符,編譯時出現(xiàn)標(biāo)識符(變量)未定義錯誤的情況。第7章編譯預(yù)處理117.1

宏定義#define第7章編譯預(yù)處理12說明:(1)帶參數(shù)的宏展開時,是用實(shí)參字符串替換形參字符串,由于運(yùn)算符的優(yōu)先級問題,可能發(fā)生的邏輯錯誤。比較好的辦法是宏定義的形參加括號。對比下面兩個例子:例一,宏定義:#defineS(r)3.14*r*r宏調(diào)用語句:area=S(a+b);宏展開后: area

=3.14*a+b*a+b;例二,宏定義:#defineS(r)3.14*(r)*(r)宏調(diào)用語句:area=S(a+b);宏展開后: area

=3.14*(a+b)*(a+b)7.1

宏定義#define下面通過例1與例2來說明它們的區(qū)別。例1int

SQ(int

y){return((y)*(y));}void

main(){int

i=1;while(i<=5)printf("%d

",SQ(i++));}例2#define

SQ(y)

((y)*(y))void

main(){int

i=1;while(i<=5)printf("%d

",SQ(i++));}7.1

宏定義#define第7章編譯預(yù)處理13第7章編譯預(yù)處理14函數(shù)調(diào)用和宏調(diào)用二者在形式上相似,在本質(zhì)上是完全不同的?,F(xiàn)將它們的區(qū)別歸納如表所示:區(qū)別項(xiàng)目函數(shù)宏信息傳遞實(shí)參的值或地址傳送給形參。用實(shí)參的字符串替換形參。處理時刻、內(nèi)存分配情況程序運(yùn)行時處理,分配臨時內(nèi)存單元。宏展開在預(yù)編譯時處理,不存在分配內(nèi)存的問題。參數(shù)類型實(shí)參和形參類型一致。如不一致,編譯器進(jìn)行類型轉(zhuǎn)換作字符串替換,不存在參數(shù)。類型問題。返回值可以有一個返回值。作字符串替換,不存在返回值問題。對源程序的影響無影響。宏展開后使程序加長。時間占用占用程序運(yùn)行時間。占用編譯時間。7.1

宏定義#define第7章編譯預(yù)處理運(yùn)行結(jié)果如下:

exp=515(4)宏定義中,若替換字符串中的形式參數(shù)在引號中,則宏展開時不被實(shí)參替換。但如果在替換字符串中,形式參數(shù)以#作為前綴,那么宏展開時它將被帶引號的實(shí)參字符串替換,如:#define

MYPRINT1(exp)

printf("exp=%d\n",exp)#define

MYPRINT2(exp)

printf(#exp"=%d\n",exp)void

main(){MYPRINT1(2+3);/*宏展開print("exp=%d\n",2+3);*/MYPRINT2(2+3);/*宏展開print("2+3""=%d\n",2+3);*//*其中字符串被連接起來,即print("2+3=%d\n",2+3);*/}7.1

宏定義#define7.2

文件包含命令#include所謂“文件包含”,是指一個原文件可以將另外一個原文件的所有內(nèi)容包含進(jìn)來。其使用格式為:#include“文件名”

或:#include

<文件名>例如,在前面我們已多次用此命令包含過庫函數(shù)的頭文件:#include

“stdio.h”/*包含標(biāo)準(zhǔn)輸入輸出頭文件*/#include

“math.h”/*包含數(shù)學(xué)函數(shù)頭文件*/#include

“string.h”*//*包含字符串處理函數(shù)頭文件文件包含命令的功能是在預(yù)處理時,把“文件名”指定的文件內(nèi)容復(fù)制到本文件(即是用指定文件的內(nèi)容去替換#

include命令行),再對合并后的文件進(jìn)行編譯。第7章編譯預(yù)處理16main(){…abc();}………int

abc(){xyz();.}int

xyz(){…..}File1.cFile2.c

File3.c#include

"file2.c"#include

"file3.c"main(){…abc();}第7章編譯預(yù)處理17File1.c這樣可以直接編譯file1,而不必人工將file2,file3內(nèi)容合并到一個文件中。7.2

文件包含命令#include第7章編譯預(yù)處理18例.

改寫求輸出圓面積的程序?yàn)閮蓚€文件。文件一:文件名為Area.h;文件內(nèi)容如下:#define

PI

3.1415926535#define

S(r)

PI*r*r文件二:文件名為myfile.c;文件內(nèi)容如下:

#include

"Area.h"/*在預(yù)處理時,此處替換為文件Area.h的內(nèi)容*/void

main(){ float

a,

area;a

=

5;area

=

S(a);printf("r=%f\narea=%f\n",a,area);}7.2

文件包含命令#include說明:(1)#include命令中,文件名可以用雙引號括起來,也可以用尖括號括起來。例如以下寫法都是允許的:#include"stdio.h"#include<math.h>如果文件名是用引號括起來的,那么就先在源程序所在的位置查找該文件,若找不到,再到存放C庫函數(shù)頭文件所在的目錄中去查找;如果文件名是用尖括號“<”和“>”括起來的,那么直接到存放C庫函數(shù)頭文件所在的目錄中去查找。第7章編譯預(yù)處理197.2

文件包含命令#include第7章編譯預(yù)處理20(2)一個#include命令只能包含一個文件,如果要包含多個文件,要用多個#include命令。當(dāng)然,被包含的文件本身也可以使用#include命令去包含別的文件,即使用嵌套的文件包含。file1.cfile2.hfile3.hfile1.cfile2.cfile3.c(a)(b)7.2

文件包含命令#include第7章編譯預(yù)處理21(3)從理論上說,#include命令可以包含任何類型的文件,只要這些文件的內(nèi)容被擴(kuò)展后符合C語言語法。一般

#include命令用于包含擴(kuò)展名為.h的“頭文件”,如

stdio.h、string.h、math.h。在這些文件中,一般定義符

號常量、宏,或聲明函數(shù)原型。(4)被包含的文件與其所在的文件,在預(yù)處理后,成為一個文件,因此,如果被包含文件定義有全局變量,在其所在文件中不必用extern關(guān)鍵字聲明。但一般不在被包含文件中定義變量。7.2

文件包含命令#include第7章編譯預(yù)處理227.3

條件編譯命令預(yù)處理程序提供了條件編譯的功能。可以按不同的條件去編譯不同的程序部分,因而產(chǎn)生不同的目標(biāo)代碼文件。條件編譯有三種形式:1.第一種形式:#ifdef

標(biāo)識符程序段1[#else程序段2]

#endif第一種形式:如果標(biāo)識符已被

#define命令定義過則對程序段1進(jìn)行編譯;否則對程序段2進(jìn)行編譯。如果沒有程序段2(它為空),本格式中的#else可以沒有。第7章編譯預(yù)處理232.第二種形式:#ifndef

標(biāo)識符程序段1[#else程序段2]

#endif3.第三種形式:#if

表達(dá)式程序段1#else程序段2#endif第二種形式:如果標(biāo)識符未被#define命令定義過則對程序段1進(jìn)行編譯,否則對程序段2進(jìn)行編譯。這與第一種形式的功能正相反。第三種形式:表達(dá)式為常量整型表達(dá)式(其中不能包含sizeof、強(qiáng)制類型轉(zhuǎn)換運(yùn)算符或枚舉常量),如表達(dá)式的值為真(非0),則對程序段1進(jìn)行編譯,否則對程序段2進(jìn)行編譯。7.3

條件編譯命令第7章編譯預(yù)處理24例.

根據(jù)是否定義VOL宏,決定是計(jì)算球的體積還是表面積:#define

PI

3.1415926#define

VOL(r)

4.0/3*PI*(r)*(r)*(r)void

main(){ double

r,v,s;printf("Enter

The

Radius\n");scanf("%lf",&r);#ifdef

VOLv=VOL(r);printf("The

Vol=%lf\n",v);#elses=4*PI*r*r;printf("The

Area=%lf\n",s);#endif}程序中,如果沒第2行的宏定義,系統(tǒng)編譯求球體表面積的那一段程序,而計(jì)算體積的那段程序就不編譯。讀者思考,如果不用條件編譯,而改用if條件語句來控制是否可以做到。7.3

條件編譯命令7.4

應(yīng)用程序舉例7.4.1

建立自己的頭文件#include命令通常用來把標(biāo)準(zhǔn)庫頭文件包含到程序中。在這些頭文件中,一般定義符號常量、宏、聲明函數(shù)原型、類型定義或結(jié)構(gòu)模板定義。理論上,#include命令可以包含任何類型的文件,只要這些文件的內(nèi)容被擴(kuò)展后符合C語言語法,通常是擴(kuò)展名為.h的頭文件。因此,許多程序員開發(fā)自己的標(biāo)準(zhǔn)頭文件,以便在程序中使用。如果是在開發(fā)一系列相關(guān)的函數(shù)和結(jié)構(gòu),那么這種方法特別有價值。另外,可以使用頭文件來聲明多個文件共享的外部變量。第7章編譯預(yù)處理25第7章編譯預(yù)處理26例7-12創(chuàng)建一個用于處理學(xué)生信息的頭文件,文件名為myhead.h,它包含常量定義、學(xué)生信息全局變量的定義及函數(shù)原型說明。/*學(xué)生人數(shù)最大值*//*學(xué)生姓名字符最大值*//*課程數(shù)*/#define

STU_NUM

20#define

NAME_LEN

50#define

COURSE_NUM

3/*學(xué)生信息全局變量的定義*/char

name[STU_NUM][NAME_LEN];/*學(xué)生姓名*//*學(xué)生成績*//*學(xué)生平均成績*/int

score[STU_NUM][COURSE_NUM];float

ave[STU_NUM];/*函數(shù)原型*/voidget_info();/*輸入學(xué)生信息*/voidget_ave();/*求每個學(xué)生的平均成績*/voidprint_info();/*輸出學(xué)生信息*/7.4

應(yīng)用程序舉例第7章編譯預(yù)處理27例7-13編寫一個處理學(xué)生信息的C程序文件,文件名student.c,程序代碼如下:/*函數(shù)定義*/void

get_info(){inti,j;for(i=0;i<STU_NUM;i++){

scanf("%s",name[i]);for(j=0;j<COURSE_NUM;j++)}}void

get_ave(){inti,j;for(i=0;i<STU_NUM;i++){

ave[i]=0;for(j=0;j<COURSE_NUM;j++)ave[i]/=

COURSE_NUM;}}scanf("%d",score[i][j]);/*函數(shù)定義*/ave[i]+=score[i][j];7.4

應(yīng)用程序舉例第7章編譯預(yù)處理28void

print_info(){inti,j;for(i=0;i<STU_NUM;i++){printf("%s's

score:\n",name[i]);for(j=0;j<COURSE_NUM;j++)printf("%d\t",score[i][j]);/*函數(shù)定義*/printf("\nthe

ave

score

is

%f.\n",ave[i]);}}7.4

應(yīng)用程序舉例第7章編譯預(yù)處理29例7-14使用例7-12建立的頭文件和例7-13建立的處理學(xué)生信息的C程序,利用它們構(gòu)成一個處理學(xué)生信息的一個完整C程序,程序文件名為stumain.c,程序如下:#include

<stdio.h>#include

“myhead.h”

/*將自己編寫的頭文件包含進(jìn)來*/#include

"student.c"/*將處理學(xué)生信息的程序文件包含進(jìn)來*/void

main(){get_info();get_ave();print_info();}7.4

應(yīng)用程序舉例說明:本程序的代碼分別存于3個文件中,包含主函數(shù)的通常稱其為主文件,一般它通過文件包含命令“#include”將其他文件包含到該文件,相當(dāng)于將其他文件中的代碼復(fù)制到

#include命令處。一個大型的C程序可以由多個文件組成,可以通過文件包含命令將它們組織起來執(zhí)行。第7章編譯預(yù)處理307.4

應(yīng)用程序舉例第7章編譯預(yù)處理31練

習(xí)判斷題宏定義的命令行可以看作是一條C語句。填空題定義一個帶參數(shù)的宏,若變量中的字符為大寫字母,則轉(zhuǎn)換為小寫字母。定義一個帶參數(shù)的宏,將兩個參數(shù)值交換#defineswap(a,b){doublet;

}寫出下列程序段的輸出結(jié)果

。#define

T

16#define

S

(T+10)-7main(){

printf("%d\n",

S*2);

}練

習(xí)下列宏定義命令中,哪一個格式是正確的( )。A、#define

pi=3.14159;C、#define

pi

"3.14159"B、define

pi=3.14159

D、#define

pi(3.14159);定義帶參數(shù)的宏計(jì)算兩個表達(dá)式的乘積,下列定義中哪個是正確的( )。A、#define

muit(u,

v)

u*vC、#define

muit(u,

v)

(u)*(v)B、#define

muit(u,

v)

u*v;D、#define

muit(u,

v)=(u)*(v)宏定義為:#define

div(a,

b)

a/b;

對語句“printf("div(a,b)=%d\n",div(x+5,

y-5));”作宏替換后為( )。A、printf("div(a,

b)=%d\n",

x+5/y-5;);B、printf("a/b=%d\n",

x+5/y-5);C、printf("a/b=%d\n",

(x+5)/(y-5));D、printf("a/b=%d\n",

x+5/y-5;);第7章編譯預(yù)處理32第7章編譯預(yù)處理33

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(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)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論