




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第11章編譯預(yù)處理11.1宏定義11.2條件編譯11.3文件包含本章小結(jié)
11.1宏定義
在C語言源程序中允許用一個標(biāo)識符來表示一個字符串,稱之為“宏”。被定義為“宏”的標(biāo)識符稱為“宏名”。在編譯預(yù)處理時,對程序中所有出現(xiàn)的“宏名”,都用宏定義中的字符串去代換,這稱為“宏代換”或“宏展開”。宏定義是由源程序中的宏定義命令完成的。宏代換是由預(yù)處理程序自動完成的。
“宏”并不是一個陌生的概念,在前面使用的符號常量就是宏。宏最簡單的情況是用一個標(biāo)識符代表一個數(shù)值,這屬于不帶參數(shù)的宏。在使用中,宏還有一種復(fù)雜的形式,可以使用參數(shù),即帶參數(shù)的宏。11.1.1不帶參數(shù)的宏定義
不帶參數(shù)宏定義的一般形式為
#define宏標(biāo)識符宏標(biāo)識符代表的特定的字符串
其中:“#”表示這是一條預(yù)處理命令;“define”為宏定義命令;“標(biāo)識符”為所定義的宏名;“字符串”可以是常數(shù)、表達式、格式串等。在這種宏定義里宏名后不帶參數(shù)。
在前面的章節(jié)中所使用的符號常量定義方法其實就是一種不帶參數(shù)的宏定義。例如:
#definePI3.14159265這里定義了一個名為PI的宏,其代表的字符串為3.14159265。作為一種編碼規(guī)范,習(xí)慣用大寫字母來表示標(biāo)識符,以區(qū)別于一般變量標(biāo)識符。
此外,采用不帶參數(shù)的宏定義形式還可以對程序中反復(fù)使用的表達式進行定義。例如:
#defineD(b*b-4*a*c)
表示程序中所有的表達式(b*b-4*a*c)都可由D代替。在編譯源程序時,先進行宏替換,即用表達式(b*b-4*a*c)去替換所有的宏名D,然后再進行編譯。不帶參數(shù)的宏定義形式可以代表一個字符串常量。例如:
#defineVERSION"Version1.0Copyright(c)2012"
這里定義了一個名為VERSION的宏,代表了字符串"Version1.0Copyright(c)2012"。
【例11.1】
無參數(shù)宏定義代表字符串和數(shù)值變量。
程序如下:
#defineNUMBER16
#defineMSG“Weloveclanguage.”
#defineFMT“numberis%d\n”
main()
{
intnumber=NUMBER;
printf(FMT,number);
printf("%s\n",MSG);
}程序運行結(jié)果:
numberis16
Weloveclanguage.
編譯預(yù)處理情況:函數(shù)體中的NUMBER被數(shù)值16替換,MSG被字符串?“Weloveclanguage.”?替換,F(xiàn)MT被字符串?“numberis%d\n”?替換。預(yù)處理后的程序如下:
main()
{
intnumber=16;
printf(“numberis%d\n”,number);
printf(“%s\n”,“Weloveclanguage.”);
}11.1.2帶參數(shù)的宏定義
在C語言中,宏定義也可以帶參數(shù),其定義形式為
#define宏標(biāo)識符(形參表)字符串
這里要求形參表中的參數(shù)要在字符串中出現(xiàn),調(diào)用的一般形式為
宏名(實參表)
宏定義中的參數(shù)為形參,宏調(diào)用中的參數(shù)為實參。例如:
#defineSQUARE(a)a*a
若程序中有以下語句:
m=SQUARE(2.5);在宏調(diào)用時,用實參2.5代替形參a,經(jīng)預(yù)處理宏替換后的語句為
m=2.5*2.5
在編程過程中,經(jīng)常用到如下的一些帶參數(shù)的宏定義:
#defineMAX(a,b) (((a)>(b))?(a):(b))
#defineMIN(a,b) (((a)<(b))?(a):(b))
#defineABS(x) (((x)>0)?(x):(-(x)))
#defineSTREQ(s1,s2) (strcmp((s1),(s2))==0)
#defineSTRGT(s1,s2) (strcmp((s1),(s2))>0)
【例11.2】
使用帶參數(shù)宏定義求兩個數(shù)中的最大值。
程序如下:
#include<stdio.h>
#defineMAX(x,y)((x>y)?x:y) /*帶參數(shù)的宏定義*/
voidmain()
{
inta,b;
a=6;
b=9;
printf(“Maxnumberis”,MAX(a,b));
/*調(diào)用帶參數(shù)的宏*/
}程序運行結(jié)果:
Maxnumberis9
在程序中,MAX(a,b)經(jīng)過編譯預(yù)處理后的形式為
((a>b)?a:b)
帶參數(shù)的宏與函數(shù)在形式和使用上有一些相似之處,但它與函數(shù)是不同的,主要的差別如下:
①函數(shù)調(diào)用時,先求出實參表達式的值,然后代入形參;而使用帶參數(shù)的宏,則只是進行簡單的字符替換,不進行計算。②函數(shù)調(diào)用是在程序運行時處理的,需要分配臨時的內(nèi)存單元;而宏展開則是在編譯時進行的,在展開時并不分配內(nèi)存單元,也不進行值傳遞處理,沒有“返回值”的概念。
③對函數(shù)中的實參和形參都要定義類型,二者的類型要求一致,如果不一致,則應(yīng)進行類型轉(zhuǎn)換;而宏不存在類型問題,宏名無類型,它的參數(shù)也無類型,只是一個符號代表,展開時代入指定的字符即可。宏定義時,字符串可以是任何類型的數(shù)據(jù)。④調(diào)用函數(shù)只可得到一個返回值,而用宏可以得到幾個結(jié)果。例如,有宏定義語句:
#defineCIRCLE(R,L,S,V)L=2*PI*R;S=PI*R*R;V=4.0/3.0*PI*R*R*R
則當(dāng)調(diào)用這個宏時,可以得到3個結(jié)果。
⑤使用宏次數(shù)多時,宏展開后源程序會變長;而函數(shù)調(diào)用不會使源程序變長。
⑥宏替換不占運行時間,只占編譯時間;而函數(shù)調(diào)用則占運行時間。一般用宏來代表簡短的表達式比較合適。
【例11.3】利用宏定義求三個數(shù)中的最大數(shù)。
程序如下:
#include“stdio.h”
#definemax(x,y)x>y?x:y
main()
{
inta,b,c,m;
scanf(“%d%d%d”,&a,&b,&c);
m=max(a,b);
/*使用宏max,a、b為宏實參*/
printf(“max=%d\n”,max(m,c));
/*使用宏max,m、c為宏實參*/
}
程序運行結(jié)果:
6611738
max=117
【例11.4】計算圓的周長和面積。
程序如下:
#definePI3.1415926
#defineCIRCLE(R,L,S)L=2*PI*R;S=PI*R*R;
main()
{
floatr,l,s;
printf(“Inputr:”);
scanf(“%f”,&r);
CIRCLE(r,l,s); /*源程序中使用帶參數(shù)的宏*/
printf("L=%f,S=%f\n",l,s);
}預(yù)處理后的程序代碼:
main()
{
floatr,l,s;
printf(“Inputr:”);
scanf(“%f”,&r);
l=2*PI*r;s=PI*r*r; /*這兩條語句由CIRCLE(r,l,s)宏替換后生成*/
printf(“L=%f,S=%f\n”,l,s);
}
程序運行結(jié)果:
Inputr:5.6
L=35.185837,S=98.52034611.1.3宏嵌套
宏定義可以嵌套,即可以在一個宏定義中使用另一個宏。例如:
#defineM 5
#defineN M+1
#defineSQUARE(x) ((x)*(x))
#defineCUBE(x) (SQUARE(x)*(x))
#defineSIXTH(x) (CUBE(x)*CUBE(x))
預(yù)處理器在處理這樣的嵌套宏時擴展每個#define,直到程序中不再有宏為止。比如,最后一個宏定義的第一次擴展為
(SQUARE(x)*(x))*(SQUARE(x)*(x))
SQUARE(x)仍是一個宏,因而進一步擴展為
((((x)*(x))*(x))*(((x)*(x))*(x)))
此外,一個宏還可以用做另一個宏的參數(shù)。例如,可以定義以下的宏來計算兩者的最大值:
#defineMAX(a,b)(((a)>(b))?(a):(b))
在此定義的基礎(chǔ)上,嵌套使用宏MAX(x,MAX(y,z))就可以得出x,y,z的最大值。
C語言還為我們提供了取消宏的定義方式,其形式為
#undef標(biāo)識符
這種定義可以把某個宏的作用范圍限制在程序的某一部分中。
11.2條件編譯
C語言中的預(yù)處理器提供了條件編譯功能。通常情況下,源程序中所有的行均參加編譯,但如果代碼較長,則有必要對程序有選擇性地進行編譯。C語言中的條件編譯給我們提供了這樣的功能,即當(dāng)滿足條件時對一組語句進行編譯,當(dāng)不滿足條件時則編譯另一組語句,進而產(chǎn)生不同的目標(biāo)代碼文件。這樣可以大大提高程序的可移植性。條件編譯有以下三種形式:
第一種形式:
#ifdef標(biāo)識符
程序段1
#else
程序段2
#endif
該程序段的功能是,如果標(biāo)識符已被?#define命令定義過,則對程序段1進行編譯,否則對程序段2進行編譯。如果沒有程序段2(它為空),則本格式中的?#else可以沒有,即可以寫為
#ifdef標(biāo)識符
程序段
#endif
第二種形式:
#ifndef標(biāo)識符
程序段1
#else
程序段2
#endif第二種形式與第一種形式的最大區(qū)別在于將“ifdef”改為“ifndef”。該程序段的功能是,如果標(biāo)識符未被?#define命令定義過,則對程序段1進行編譯,否則對程序段2進行編譯。這與第一種形式的功能正好相反。
第三種形式:
#if常量表達式
程序段1
#else
程序段2
#endif該程序段的功能是,如果常量表達式的值為真(非0),則對程序段1進行編譯,否則對程序段2進行編譯。因此該形式可以使程序在不同條件下完成不同的功能。
【例11.5】輸入一行字母字符,根據(jù)需要設(shè)置條件編譯,將字符全改為大寫字母輸出,或全改為小寫字母輸出。
程序如下:
#include<stdio.h>
#defineLETTER1
voidmain()
{
charc,str[20]=“CLanguage”;
inti=0;
while((c=str[i])!='\0')
{
i++;
#ifLETTER
if(c>=‘a(chǎn)’&&c<=‘z’)
c=c-32; /*宏LETTER定義表示“真”時運行*/
#else
if(c>=‘A’&&c<=‘Z’)
c=c+32; /*宏LETTER定義表示“假”時運行*/
#endif
printf(“%c\n”,c);
}
}
程序運行結(jié)果:
CLANGUAGE如果將程序第一行改為“#defineLETTER0”,則在預(yù)處理時,對第二個if語句進行編譯處理,使大寫字母變成小寫字母。此時,程序運行結(jié)果為
clanguage
【例11.6】分析以下程序中宏語句的功能。
程序如下:
#include<stdio.h>
voidmain()
{
floatr,s;
printf("pleaseinputradius:");
scanf("%f",&r);
#ifdefPI
s=PI*r*r; /*宏P(guān)I在該語句之前定義時執(zhí)行*/
#else
#definePI3.14159265 /*宏P(guān)I在該語句之前未定義時執(zhí)行*/
s=PI*r*r;
#endif
printf("s=%f\n",s);
}
程序運行結(jié)果:
pleaseinputradius:1.0↙
s=3.1415927
在此例中,如果PI被事先定義則執(zhí)行語句s=PI*r*r,否則對PI進行宏定義。
11.3文件包含
在C語言中,程序可以包含外部文件,這些外部文件通常包含函數(shù)或宏定義等元素。文件包含是C預(yù)處理程序的重要功能,該功能可以由以下的預(yù)處理指令來實現(xiàn):
#include"文件名"
在前面我們已多次用此命令包含過庫函數(shù)的頭文件。例如:
#include"stdio.h"
#include"math.h"預(yù)處理器遇到這樣的語句時,將文件名對應(yīng)的整個內(nèi)容插入到程序的源代碼中。在程序設(shè)計中,文件包含是很有用的。一個大的程序可以分為多個模塊,由多個程序員分別編程。有些公用的符號常量或宏定義等可單獨組成一個文件,在其他文件的開頭用包含命令包含該文件即可使用。這樣,可避免在每個文件開頭都書寫那些公用量,從而節(jié)省了時間,并減少了出錯概率。
包含命令中的文件名除了可以用雙引號括起來外,也可以用尖括號括起來。例如以下寫法都是允許的:
#include<stdio.h>
#include<math.h>但是這兩種形式是有區(qū)別的:使用尖括號表示只在標(biāo)準(zhǔn)目錄中查找該文件,而不在源文件目錄中查找;使用雙引號則表示首先從當(dāng)前目錄中查找該文件,若未找到再在標(biāo)準(zhǔn)目錄中查找。用戶編程時可根據(jù)自己文件所在的目錄來選擇某一種命令形式。如果在編譯過程中沒有找到被包含的文件,將報告一個錯誤,且終止編譯。此外,文件包含允許嵌套,即在一個被包含的文件中又可以包含另一個文件,但是文件不能包含自身。一個include命令只能指定一個被包含文件,若有多個文件要包含,則需用多個include命令。
【例11.7】創(chuàng)建文件userdef.h并在程序中使用它。
以下是userdef.h文件的內(nèi)容:
#definePRINTprintf /*定義符號常量PRINT*/
#defineINPUTscanf /*定義符號常量INPUT*/
#definePI3.1415926 /*定義符號常量PI*/在下面的程序中使用userdef.h
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 小區(qū)車位租賃合同15篇
- 漢字字謎課件
- 漢字基礎(chǔ)知識培訓(xùn)方案課件
- T-GRM 114-2025 富油煤原位熱解術(shù)語
- DB4403-T 369-2023 大型活動溫室氣體排放核算和報告指南
- 2024年秋新北師大版數(shù)學(xué)一年級上冊教學(xué)課件 第一單元 生活中的數(shù) 1我上學(xué)啦
- 公路應(yīng)急儲備設(shè)備檢修方案
- 消防安全培訓(xùn)實施方案
- 建筑工程項目基坑支護與加固方案
- 機電設(shè)備安裝技術(shù)創(chuàng)新應(yīng)用方案
- 全國托育職業(yè)技能競賽理論考試題及答案
- HSK標(biāo)準(zhǔn)教程1-第一課lesson1
- 2022新能源光伏電站電力監(jiān)控系統(tǒng)安全防護實施方案
- 新課標(biāo)人教版七年級數(shù)學(xué)上冊教案全冊
- 人教版小學(xué)英語3-6年級單詞(帶音標(biāo))
- 酒店消防安全管理制度(2022版)
- 2024環(huán)氧磨石地坪施工技術(shù)規(guī)程
- 人教部編七年級語文全冊專項知識點梳理歸納字詞、文言文、古詩詞
- 2022年版初中物理課程標(biāo)準(zhǔn)解讀-課件
- 輸配電絕緣子維護與更換
- 幼兒園教師讀《讓兒童的學(xué)習(xí)看得見》有感
評論
0/150
提交評論