《C語言程序設(shè)計 》課件第11章_第1頁
《C語言程序設(shè)計 》課件第11章_第2頁
《C語言程序設(shè)計 》課件第11章_第3頁
《C語言程序設(shè)計 》課件第11章_第4頁
《C語言程序設(shè)計 》課件第11章_第5頁
已閱讀5頁,還剩30頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論