




版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 燈具改造施工方案
- 鋼材基礎(chǔ)知識培訓(xùn)課件
- 吊頂裝飾工程合同范例
- 刀具合同范例
- 如何建立與維護(hù)良好的銀行關(guān)系計(jì)劃
- 行業(yè)趨勢研究與應(yīng)對措施計(jì)劃
- 筑夢未來社團(tuán)工作愿景計(jì)劃
- 人力資源戰(zhàn)略與公司目標(biāo)的對接計(jì)劃
- 注重員工心理健康的年度計(jì)劃
- 餐飲行業(yè)安全消防工作計(jì)劃
- 跨國合作在醫(yī)藥研發(fā)中的應(yīng)用與挑戰(zhàn)
- 2025年皖北衛(wèi)生職業(yè)學(xué)院單招職業(yè)技能測試題庫審定版
- 膀胱灌注課件
- 2025年足療店勞務(wù)用工合同模板
- 北京版五年級下冊數(shù)學(xué)計(jì)算題專項(xiàng)練習(xí)1000道帶答案
- 《陸上風(fēng)電場工程概算定額》NBT 31010-2019
- JTGT F20-2015 公路路面基層施工技術(shù)細(xì)則
- 2024年江蘇省農(nóng)墾集團(tuán)有限公司招聘筆試參考題庫含答案解析
- GB/T 15558.2-2023燃?xì)庥寐竦鼐垡蚁?PE)管道系統(tǒng)第2部分:管材
- 267條表情猜成語【動畫版】
- 繪本《一園青菜成了精》
評論
0/150
提交評論