單片機(jī)應(yīng)用技術(shù)-第6章-C語言程序設(shè)計(jì)及仿真調(diào)試課件_第1頁
單片機(jī)應(yīng)用技術(shù)-第6章-C語言程序設(shè)計(jì)及仿真調(diào)試課件_第2頁
單片機(jī)應(yīng)用技術(shù)-第6章-C語言程序設(shè)計(jì)及仿真調(diào)試課件_第3頁
單片機(jī)應(yīng)用技術(shù)-第6章-C語言程序設(shè)計(jì)及仿真調(diào)試課件_第4頁
單片機(jī)應(yīng)用技術(shù)-第6章-C語言程序設(shè)計(jì)及仿真調(diào)試課件_第5頁
已閱讀5頁,還剩76頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

第6章C語言程序設(shè)計(jì)及仿真調(diào)試

6.1C語言程序設(shè)計(jì)基礎(chǔ)

6.2KeilC對(duì)

ANSIC的擴(kuò)展6.1C語言程序設(shè)計(jì)基礎(chǔ)

6.1.1數(shù)據(jù)類型

1.基本數(shù)據(jù)類型基本數(shù)據(jù)類型不可以再分解為其他類型。2.構(gòu)造數(shù)據(jù)類型·數(shù)組類型·結(jié)構(gòu)類型·聯(lián)合類型3.指針類型用來表示某個(gè)量在內(nèi)存中的地址。4.空類型調(diào)用后不需要向調(diào)用者返回值的函數(shù)為“空類型”。其類型說明符為void。6.1.2基本運(yùn)算符和表達(dá)式

1.運(yùn)算符的種類

豐富的運(yùn)算符和表達(dá)式使C語言功能十分完善。這也是其主要特點(diǎn)之一。C語言的運(yùn)算符不僅具有不同的優(yōu)先級(jí),而且還具有結(jié)合性。在表達(dá)式中,各運(yùn)算量參與運(yùn)算的先后順序不僅要遵守運(yùn)算符優(yōu)先級(jí)別的規(guī)定,還要受運(yùn)算符結(jié)合性的制約,以便確定是自左向右進(jìn)行運(yùn)算還是自右向左進(jìn)行運(yùn)算。C語言的運(yùn)算符可分為以下幾類:

算術(shù)運(yùn)算符:用于各類數(shù)值運(yùn)算。包括加(+)、減(-)、乘(×)、除(/)、求余(或稱模運(yùn)算,%)、自增(++)、自減(--)共七種。

關(guān)系運(yùn)算符:用于比較運(yùn)算。包括大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)和不等于(!=)六種。

邏輯運(yùn)算符:用于邏輯運(yùn)算。包括與(&&)、或(||)、非(!)三種。

位操作運(yùn)算符:參與運(yùn)算的量,按二進(jìn)制位進(jìn)行運(yùn)算。包括位與(&)、位或(|)、位非(~)、位異或(^)、左移(<<)、右移(>>)六種。

賦值運(yùn)算符:用于賦值運(yùn)算,分為簡(jiǎn)單賦值(=)、復(fù)合算術(shù)賦值(+=,-=,*=,/=,%=)和復(fù)合位運(yùn)算賦值(&=,|=,^=,>>=,<<=)三類共十一種。

條件運(yùn)算符:這是一個(gè)三目運(yùn)算符,用于條件求值(?:)。

逗號(hào)運(yùn)算符:用于把若干表達(dá)式組合成一個(gè)表達(dá)式(,)。

指針運(yùn)算符:用于取內(nèi)容(*)和取地址(&)二種運(yùn)算。

求字節(jié)數(shù)運(yùn)算符:用于計(jì)算數(shù)據(jù)類型所占的字節(jié)數(shù)(sizeof)。

特殊運(yùn)算符:有括號(hào)(),下標(biāo)[],成員(→,.)等幾種。2.優(yōu)先級(jí)和結(jié)合性

C語言中,運(yùn)算符的運(yùn)算優(yōu)先級(jí)共分為15級(jí)。1級(jí)最高,15級(jí)最低。在表達(dá)式中,優(yōu)先級(jí)較高的先于優(yōu)先級(jí)較低的進(jìn)行運(yùn)算。而在一個(gè)運(yùn)算量?jī)蓚?cè)的運(yùn)算符優(yōu)先級(jí)相同時(shí),則按運(yùn)算符的結(jié)合性所規(guī)定的結(jié)合方向處理。C語言中各運(yùn)算符的結(jié)合性分為兩種,即左結(jié)合性(自左至右)和右結(jié)合性(自右至左)。例如算術(shù)運(yùn)算符的結(jié)合性是自左至右,即先左后右。如表達(dá)式x-y+z,則y應(yīng)先與“-”號(hào)結(jié)合,執(zhí)行x-y運(yùn)算,然后再執(zhí)行+z的運(yùn)算。這種自左至右的結(jié)合方向就稱為“左結(jié)合性”。而自右至左的結(jié)合方向稱為“右結(jié)合性”。最典型的右結(jié)合性運(yùn)算符是賦值運(yùn)算符。如x=y=z,由于“=”的右結(jié)合性,應(yīng)先執(zhí)行y=z再執(zhí)行x=(y=z)運(yùn)算。3.算術(shù)運(yùn)算符和算術(shù)表達(dá)式中基本的算術(shù)運(yùn)算符

加法運(yùn)算符“+”:加法運(yùn)算符為雙目運(yùn)算符,即應(yīng)有兩個(gè)量參與加法運(yùn)算。如a+b,4+8等。具有右結(jié)合性。

減法運(yùn)算符“-”:減法運(yùn)算符為雙目運(yùn)算符。但“-”也可作負(fù)值運(yùn)算符,此時(shí)為單目運(yùn)算,如-x,-5等具有左結(jié)合性。

乘法運(yùn)算符“*”:雙目運(yùn)算,具有左結(jié)合性。

除法運(yùn)算符“/”:雙目運(yùn)算具有左結(jié)合性。參與運(yùn)算量均為整型時(shí),結(jié)果也為整型,舍去小數(shù)。如果運(yùn)算量中有一個(gè)是實(shí)型,則結(jié)果為雙精度實(shí)型。

求余運(yùn)算符(模運(yùn)算符)“%”:雙目運(yùn)算,具有左結(jié)合性。要求參與運(yùn)算的量均為整型。求余運(yùn)算的結(jié)果等于兩數(shù)相除后的余數(shù)。

4.自增1,自減1運(yùn)算符

自增1運(yùn)算符記為“++”,其功能是使變量的值自增1。自減1運(yùn)算符記為“--”,其功能是使變量值自減1。自增1,自減1運(yùn)算符均為單目運(yùn)算,都具有右結(jié)合性??捎幸韵聨追N形式:++i:i自增1后再參與其他運(yùn)算。--i:i自減1后再參與其他運(yùn)算。i++:i參與運(yùn)算后,i的值再自增1。i--:i參與運(yùn)算后,i的值再自減1。5.算術(shù)表達(dá)式

算術(shù)表達(dá)式是由算術(shù)運(yùn)算符和括號(hào)連接起來的式子,以下是算術(shù)表達(dá)式的例子:a+b,(a*2)/c,(x+r)*8-(a+b)/7,++i,sin(x)+sin(y),(++i)-(j++)+(k--)。6.賦值運(yùn)算符和賦值表達(dá)式

簡(jiǎn)單賦值運(yùn)算符和表達(dá)式,簡(jiǎn)單賦值運(yùn)算符記為“=”。由“=”連接的式子稱為賦值表達(dá)式。其一般形式為:變量=表達(dá)式。例如:x=a+bw=sin(a)+sin(b)

如果賦值運(yùn)算符兩邊的數(shù)據(jù)類型不相同,系統(tǒng)將自動(dòng)進(jìn)行類型轉(zhuǎn)換,即把賦值號(hào)右邊的類型換成左邊的類型。具體規(guī)定如下:實(shí)型賦予整型,舍去小數(shù)部分。整型賦予實(shí)型,數(shù)值不變,但將以浮點(diǎn)形式存放,即增加小數(shù)部分(小數(shù)部分的值為0)。字符型賦予整型,由于字符型為一個(gè)字節(jié),而整型為二個(gè)字節(jié),故將字符的ASCII碼值放到整型量的低八位中,高八位為0。整型賦予字符型,僅把低八位賦予字符量。7.復(fù)合賦值符及表達(dá)式

在賦值符“=”之前加上其他雙目運(yùn)算符可構(gòu)成復(fù)合賦值符。如:+=,-=,*=,/=,%=,<<=,>>=,&=,^=,|=構(gòu)成復(fù)合賦值表達(dá)式的一般形式為:

變量雙目運(yùn)算符=表達(dá)式

它等效于:

變量=變量運(yùn)算符表達(dá)式

例如:a+=5等價(jià)于a=a+5,x*=y+7等價(jià)于x=x*(y+7),r%=p等價(jià)于r=r%p等。復(fù)合賦值符這種寫法,對(duì)初學(xué)者可能不習(xí)慣,但十分有利于編譯處理,能提高編譯效率并產(chǎn)生質(zhì)量較高的目標(biāo)代碼。8.逗號(hào)運(yùn)算符

C語言中逗號(hào)“,”也是一種運(yùn)算符,稱為逗號(hào)運(yùn)算符。其功能是把兩個(gè)表達(dá)式連接起來組成一個(gè)表達(dá)式,稱為逗號(hào)表達(dá)式。其一般形式為:表達(dá)式1,表達(dá)式2;其求值過程是分別求兩個(gè)表達(dá)式的值,并以表達(dá)式2的值作為整個(gè)逗號(hào)表達(dá)式的值。6.1.3C語言程序設(shè)計(jì)

從程序流程的角度來看,程序可以分為三種基本結(jié)構(gòu),即:順序結(jié)構(gòu)分支結(jié)構(gòu)循環(huán)結(jié)構(gòu)這三種基本結(jié)構(gòu)可以組成所有的各種復(fù)雜程序。C語言提供了多種語句來實(shí)現(xiàn)這些結(jié)構(gòu)。1.分支結(jié)構(gòu)程序(1)if語句

用if語句可以構(gòu)成分支結(jié)構(gòu)。它根據(jù)給定的條件進(jìn)行判斷,以決定執(zhí)行某個(gè)分支程序段。C語言的if語句有三種基本形式。第一種形式為基本形式:if(表達(dá)式)語句其語義是:如果表達(dá)式的值為真,則執(zhí)行其后的語句,否則不執(zhí)行該語句。第二種形式為:if-elseif(表達(dá)式)語句1;else

語句2;其語義是:如果表達(dá)式的值為真,則執(zhí)行語句1,否則執(zhí)行語句2。第三種形式為:if-else-if

前二種形式的if語句一般都用于兩個(gè)分支的情況。當(dāng)有多個(gè)分支選擇時(shí),可采用if-else-if語句,其一般形式為:if(表達(dá)式)語句1;elseif(表達(dá)式2)語句2;elseif(表達(dá)式3)語句3;elseif(表達(dá)式m)

語句m;else

語句n;

其語義是:依次判斷表達(dá)式的值,當(dāng)出現(xiàn)某個(gè)值為真時(shí),則執(zhí)行其對(duì)應(yīng)的語句。然后跳到整個(gè)if語句之外繼續(xù)執(zhí)行程序。如果所有的表達(dá)式均為假,則執(zhí)行語句n。然后繼續(xù)執(zhí)行后續(xù)程序。(2)switch語句

C語言還提供了另一種用于多分支選擇的switch語句,其一般形式為:switch(表達(dá)式){case常量表達(dá)式1:語句體1;case常量表達(dá)式2:語句體2;…case常量表達(dá)式n:語句體n;default:語句體n+1;}

其語義是:計(jì)算表達(dá)式的值,并逐個(gè)與其后的常量表達(dá)式值相比較,當(dāng)表達(dá)式的值與某個(gè)常量表達(dá)式的值相等時(shí),即執(zhí)行其后的語句體。一般語句體中包含break語句,所以執(zhí)行完語句體后,不再進(jìn)行判斷其他的case語句,直接執(zhí)行switch語句后面的程序。如表達(dá)式的值與所有case后的常量表達(dá)式均不相同時(shí),則執(zhí)行default后的語句體。2.循環(huán)結(jié)構(gòu)程序

循環(huán)結(jié)構(gòu)是程序中一種很重要的結(jié)構(gòu)。其特點(diǎn)是,在給定條件成立時(shí),反復(fù)執(zhí)行某程序段,直到條件不成立為止。給定的條件稱為循環(huán)條件,反復(fù)執(zhí)行的程序段稱為循環(huán)體。C語言提供了多種循環(huán)語句,可以組成各種不同形式的循環(huán)結(jié)構(gòu)。

(1)while語句

while語句的一般形式為:while(表達(dá)式)語句;其中表達(dá)式是循環(huán)條件,語句為循環(huán)體。while語句的語義是:計(jì)算表達(dá)式的值,當(dāng)值為真(非0)時(shí),執(zhí)行循環(huán)體語句。(2)do-while語句

do-while語句的一般形式為:do

語句;while(表達(dá)式);其中語句是循環(huán)體,表達(dá)式是循環(huán)條件。do-while語句的語義是:先執(zhí)行循環(huán)體語句一次,再判別表達(dá)式的值,若為真(非0)則繼續(xù)循環(huán),否則終止循環(huán)。do-while語句和while語句的區(qū)別在于do-while是先執(zhí)行后判斷,因此do-while至少要執(zhí)行一次循環(huán)體。而while是先判斷后執(zhí)行,如果條件不滿足,則一次循環(huán)體語句也不執(zhí)行。while語句和do-while語句一般都可以相互改寫。(3)for語句

for語句是C語言所提供的功能更強(qiáng),使用更廣泛的一種循環(huán)語句。其一般形式為:for(表達(dá)式1;表達(dá)式2;表達(dá)3)語句;其中,表達(dá)式1通常用來給循環(huán)變量賦初值,一般是賦值表達(dá)式。也允許在for語句外給循環(huán)變量賦初值,此時(shí)可以省略該表達(dá)式。表達(dá)式2通常是循環(huán)條件,一般為關(guān)系表達(dá)式或邏輯表達(dá)式。表達(dá)式3通??捎脕硇薷难h(huán)變量的值,一般是賦值語句。這三個(gè)表達(dá)式都可以是逗號(hào)表達(dá)式,即每個(gè)表達(dá)式都可由多個(gè)表達(dá)式組成。三個(gè)表達(dá)式都是任選項(xiàng),都可以省略。一般形式中的“語句”即為循環(huán)體語句。for語句的語義是:1.首先計(jì)算表達(dá)式1的值。2.再計(jì)算表達(dá)式2的值,若值為真(非0)則執(zhí)行循環(huán)體一次,否則跳出循環(huán)。3.然后再計(jì)算表達(dá)式3的值,轉(zhuǎn)回第2步重復(fù)執(zhí)行。在整個(gè)for循環(huán)過程中,表達(dá)式1只計(jì)算一次,表達(dá)式2和表達(dá)式3則可能計(jì)算多次。循環(huán)體可能多次執(zhí)行,也可能一次都不執(zhí)行。3.轉(zhuǎn)移語句

程序中的語句通??偸前错樞蚍较?,或按語句功能所定義的方向執(zhí)行的。如果需要改變程序的正常流向,可以使用轉(zhuǎn)移語句。在C語言中提供了4種轉(zhuǎn)移語句:

goto,break,continue和return。

其中的return語句只能出現(xiàn)在被調(diào)函數(shù)中,用于返回主調(diào)函數(shù)。(1)goto語句

goto語句也稱為無條件轉(zhuǎn)移語句,其一般格式如下:

goto

語句標(biāo)號(hào);其中語句標(biāo)號(hào)是按標(biāo)識(shí)符規(guī)定書寫的符號(hào),放在某一語句行的前面,標(biāo)號(hào)后加冒號(hào)(:)。語句標(biāo)號(hào)起標(biāo)識(shí)語句的作用,與goto語句配合使用。

(2)break語句

break語句只能用在switch語句或循環(huán)語句中,其作用是跳出switch語句或跳出本層循環(huán),轉(zhuǎn)去執(zhí)行后面的程序。由于break語句的轉(zhuǎn)移方向是明確的,所以不需要語句標(biāo)號(hào)與之配合。break語句的一般形式為:break;

使用break語句可以使循環(huán)語句有多個(gè)出口,在一些場(chǎng)合下使編程更加靈活、方便。(3)continue語句

continue語句只能用在循環(huán)體中,其一般格式是:continue;

其語義是:結(jié)束本次循環(huán),即不再執(zhí)行循環(huán)體中continue語句之后的語句,轉(zhuǎn)入下一次循環(huán)條件的判斷與執(zhí)行。應(yīng)注意的是,本語句只結(jié)束本層本次的循環(huán),并不跳出循環(huán)。6.1.4函數(shù)

C語言程序是由函數(shù)組成的。函數(shù)是C源程序的基本模塊,通過對(duì)函數(shù)模塊的調(diào)用實(shí)現(xiàn)特定的功能。C語言中的函數(shù)相當(dāng)于其他高級(jí)語言的子程序。C語言不僅提供了極為豐富的庫函數(shù),還允許用戶建立自己定義的函數(shù)。用戶可把自己的算法編成一個(gè)個(gè)相對(duì)獨(dú)立的函數(shù)模塊,然后用調(diào)用的方法來使用函數(shù)??梢哉fC程序的全部工作都是由各式各樣的函數(shù)完成的,所以也把C語言稱為函數(shù)式語言。由于采用了函數(shù)模塊式的結(jié)構(gòu),C語言易于實(shí)現(xiàn)結(jié)構(gòu)化程序設(shè)計(jì)。使程序的層次結(jié)構(gòu)清晰,便于程序的編寫、閱讀、調(diào)試。1.函數(shù)定義的一般形式

(1)無參函數(shù)的一般形式

類型說明符函數(shù)名(){類型說明;語句;

}其中類型說明符和函數(shù)名稱為函數(shù)頭。類型說明符指明了本函數(shù)的類型,函數(shù)的類型實(shí)際上是函數(shù)返回值的類型。函數(shù)名是由用戶定義的標(biāo)識(shí)符,函數(shù)名后有一個(gè)空括號(hào),其中無參數(shù),但括號(hào)不可少。{}中的內(nèi)容稱為函數(shù)體。在函數(shù)體中也有類型說明,這是對(duì)函數(shù)體內(nèi)部所用到的變量的類型說明。在很多情況下都不要求無參函數(shù)有返回值,此時(shí)函數(shù)類型符可以寫為void。(2)有參函數(shù)的一般形式

類型說明符函數(shù)名(形式參數(shù)類型說明表){類型說明; 語句;}有參函數(shù)比無參函數(shù)多了兩個(gè)內(nèi)容,其一是形式參數(shù)表,其二是形式參數(shù)類型說明。在形參表中給出的參數(shù)稱為形式參數(shù),它們可以是各種類型的變量,各參數(shù)之間用逗號(hào)間隔。在進(jìn)行函數(shù)調(diào)用時(shí),主調(diào)函數(shù)將賦予這些形式參數(shù)實(shí)際的值。形參既然是變量,當(dāng)然必須給以類型說明。在程序中是通過對(duì)函數(shù)的調(diào)用來執(zhí)行函數(shù)體的,其過程與其他語言的子程序調(diào)用相似。C語言中,函數(shù)調(diào)用的一般形式為:函數(shù)名(實(shí)際參數(shù)表);對(duì)無參函數(shù)調(diào)用時(shí)則無實(shí)際參數(shù)表。實(shí)際參數(shù)表中的參數(shù)可以是常數(shù),變量或其他構(gòu)造類型數(shù)據(jù)及表達(dá)式。各實(shí)參之間用逗號(hào)分隔。2.函數(shù)的參數(shù)和函數(shù)的值

(1)函數(shù)的參數(shù)

函數(shù)的參數(shù)分為形參和實(shí)參兩種。形參出現(xiàn)在函數(shù)定義中,在整個(gè)函數(shù)體內(nèi)都可以使用,離開該函數(shù)則不能使用。實(shí)參出現(xiàn)在主調(diào)函數(shù)中,進(jìn)入被調(diào)函數(shù)后,實(shí)參變量也不能使用。形參和實(shí)參的功能是作數(shù)據(jù)傳送。發(fā)生函數(shù)調(diào)用時(shí),主調(diào)函數(shù)把實(shí)參的值傳送給被調(diào)函數(shù)的形參從而實(shí)現(xiàn)主調(diào)函數(shù)向被調(diào)函數(shù)的數(shù)據(jù)傳送。(2)函數(shù)的值

函數(shù)的值是指函數(shù)被調(diào)用之后,執(zhí)行函數(shù)體中的程序段所取得的并返回給主調(diào)函數(shù)的值。對(duì)函數(shù)的值(或稱函數(shù)返回值)有以下一些說明:a.函數(shù)的值只能通過return語句返回主調(diào)函數(shù)。return語句的一般形式為:return表達(dá)式;或者為:return(表達(dá)式);該語句的功能是計(jì)算表達(dá)式的值,并返回給主調(diào)函數(shù)。在函數(shù)中允許有多個(gè)return語句,但每次調(diào)用只能有一個(gè)return語句被執(zhí)行,因此只能返回一個(gè)函數(shù)值。b.函數(shù)值的類型和函數(shù)定義中函數(shù)的類型應(yīng)保持一致。如果兩者不一致,則以函數(shù)類型為準(zhǔn),自動(dòng)進(jìn)行類型轉(zhuǎn)換。c.如函數(shù)值為整型,在函數(shù)定義時(shí)可以省去類型說明。d.不返回函數(shù)值的函數(shù),可以明確定義為“空類型”,類型說明符為“void”。

3.函數(shù)的嵌套調(diào)用

C語言中不允許作嵌套的函數(shù)定義。因此各函數(shù)之間是平行的,不存在上一級(jí)函數(shù)和下一級(jí)函數(shù)的問題。但是C語言允許在一個(gè)函數(shù)的定義中出現(xiàn)對(duì)另一個(gè)函數(shù)的調(diào)用。這樣就出現(xiàn)了函數(shù)的嵌套調(diào)用。即在被調(diào)函數(shù)中又調(diào)用其他函數(shù)。4.函數(shù)的遞歸調(diào)用

一個(gè)函數(shù)在它的函數(shù)體內(nèi)調(diào)用它自身稱為遞歸調(diào)用。這種函數(shù)稱為遞歸函數(shù)。C語言允許函數(shù)的遞歸調(diào)用。在遞歸調(diào)用中,主調(diào)函數(shù)又是被調(diào)函數(shù)。執(zhí)行遞歸函數(shù)將反復(fù)調(diào)用其自身。每調(diào)用一次就進(jìn)入新的一層。5.變量的作用域

在討論函數(shù)的形參變量時(shí)曾經(jīng)提到,形參變量只在被調(diào)用期間才分配內(nèi)存單元,調(diào)用結(jié)束立即釋放。這一點(diǎn)表明形參變量只有在函數(shù)內(nèi)才是有效的,離開該函數(shù)就不能再使用了。這種變量有效性的范圍稱變量的作用域。不僅對(duì)于形參變量,C語言中所有的量都有自己的作用域。變量說明的方式不同,其作用域也不同。C語言中的變量,按作用域范圍可分為兩種,

即局部變量和全局變量。6.1.5指針

指針是C語言中廣泛使用的一種數(shù)據(jù)類型。運(yùn)用指針編程是C語言最主要的風(fēng)格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu);能很方便地使用數(shù)組和字符串;并能像匯編語言一樣處理內(nèi)存地址,從而編出精練而高效的程序。指針極大地豐富了C語言的功能。學(xué)習(xí)指針是學(xué)習(xí)C語言中最重要的一環(huán),能否正確理解和使用指針是我們是否掌握C語言的一個(gè)標(biāo)志。既然指針變量的值是一個(gè)地址,那么這個(gè)地址不僅可以是變量的地址,也可以是其他數(shù)據(jù)結(jié)構(gòu)的地址。在一個(gè)指針變量中存放一個(gè)數(shù)組或一個(gè)函數(shù)的首地址有何意義呢?因?yàn)閿?shù)組或函數(shù)都是連續(xù)存放的。通過訪問指針變量取得了數(shù)組或函數(shù)的首地址,也就找到了該數(shù)組或函數(shù)。這樣一來,凡是出現(xiàn)數(shù)組、函數(shù)的地方都可以用一個(gè)指針變量來表示,只要該指針變量中賦予數(shù)組或函數(shù)的首地址即可。這樣做,將會(huì)使程序的概念十分清楚,程序本身也精練、高效。在C語言中,一種數(shù)據(jù)類型或數(shù)據(jù)結(jié)構(gòu)往往都占有一組連續(xù)的內(nèi)存單元。用“地址”這個(gè)概念并不能很好地描述一種數(shù)據(jù)類型或數(shù)據(jù)結(jié)構(gòu),而“指針”雖然實(shí)際上也是一個(gè)地址,但它卻是一個(gè)數(shù)據(jù)結(jié)構(gòu)的首地址,它是“指向”一個(gè)數(shù)據(jù)結(jié)構(gòu)的,因而概念更為清楚,表示更為明確。這也是引入“指針”概念的一個(gè)重要原因。在C語言中規(guī)定,一個(gè)函數(shù)總是占用一段連續(xù)的內(nèi)存區(qū),而函數(shù)名就是該函數(shù)所占內(nèi)存區(qū)的首地址。我們可以把函數(shù)的這個(gè)首地址(或稱入口地址)賦予一個(gè)指針變量,使該指針變量指向該函數(shù)。然后通過指針變量就可以找到并調(diào)用這個(gè)函數(shù)。我們把這種指向函數(shù)的指針變量稱為“函數(shù)指針變量”。函數(shù)指針變量定義的一般形式為:類型說明符(*指針變量名)();其中“類型說明符”表示被指函數(shù)的返回值的類型?!?*指針變量名)”表示“*”后面的變量是定義的指針變量。最后的空括號(hào)表示指針變量所指的是一個(gè)函數(shù)。例如:int(*pf)();表示pf是一個(gè)指向函數(shù)入口的指針變量,該函數(shù)的返回值(函數(shù)值)是整型。6.1.6結(jié)構(gòu)與聯(lián)合

1.結(jié)構(gòu)類型定義和結(jié)構(gòu)變量說明

在實(shí)際問題中,一組數(shù)據(jù)往往具有不同的數(shù)據(jù)類型。例如,在學(xué)生登記表中,姓名應(yīng)為字符型;學(xué)號(hào)可為整型或字符型;年齡應(yīng)為整型;性別應(yīng)為字符型;成績(jī)可為整型或?qū)嵭汀o@然不能用一個(gè)數(shù)組來存放這一組數(shù)據(jù)。因?yàn)閿?shù)組中各元素的類型和長(zhǎng)度都必須一致,以便于編譯系統(tǒng)處理。為了解決這個(gè)問題,C語言中給出了另一種構(gòu)造數(shù)據(jù)類型——“結(jié)構(gòu)”。它相當(dāng)于其他高級(jí)語言中的記錄。“結(jié)構(gòu)”是一種構(gòu)造類型,它是由若干“成員”組成的。每一個(gè)成員可以是一個(gè)基本數(shù)據(jù)類型或者又是一個(gè)構(gòu)造類型。結(jié)構(gòu)既是一種“構(gòu)造”而成的數(shù)據(jù)類型,那么在說明和使用之前必須先定義它,也就是構(gòu)造它。如同在說明和調(diào)用函數(shù)之前要先定義函數(shù)一樣。(1)結(jié)構(gòu)的定義

定義一個(gè)結(jié)構(gòu)的一般形式為:

struct

結(jié)構(gòu)名{成員表列;};成員表由若干個(gè)成員組成,每個(gè)成員都是該結(jié)構(gòu)的一個(gè)組成部分。對(duì)每個(gè)成員也必須作類型說明,其形式為:類型說明符成員名;成員名的命名應(yīng)符合標(biāo)識(shí)符的書寫規(guī)定。例如:

structstudent {

intnum; charname[20]; charsex; floatscore; };

在這個(gè)結(jié)構(gòu)定義中,結(jié)構(gòu)名為student,該結(jié)構(gòu)由4個(gè)成員組成。第一個(gè)成員為num,整型變量;第二個(gè)成員為name,字符數(shù)組;第三個(gè)成員為sex,字符變量;第四個(gè)成員為score,實(shí)型變量。應(yīng)注意在括號(hào)后的分號(hào)是不可少的。結(jié)構(gòu)定義之后,即可進(jìn)行變量說明。凡說明為結(jié)構(gòu)student的變量都由上述4個(gè)成員組成。由此可見,結(jié)構(gòu)是一種復(fù)雜的數(shù)據(jù)類型,是數(shù)目固定,類型不同的若干有序變量的集合。(2)結(jié)構(gòu)類型變量的說明

說明結(jié)構(gòu)變量有以下三種方法。以上面定義的student為例來加以說明。先定義結(jié)構(gòu),再說明結(jié)構(gòu)變量。

如:

structstudent{

intnum;charname[20];charsex;floatscore;};

structstudentboy1,boy2;

說明了兩個(gè)變量boy1和boy2為student結(jié)構(gòu)類型。也可以用宏定義使一個(gè)符號(hào)常量來表示一個(gè)結(jié)構(gòu)類型,例如:

#defineSTUstructstudentSTU{

intnum;charname[20];charsex;floatscore;};STUboy1,boy2;b.在定義結(jié)構(gòu)類型的同時(shí)說明結(jié)構(gòu)變量。

例如:

structstudent{

intnum;charname[20];charsex;floatscore;}boy1,boy2;c.直接說明結(jié)構(gòu)變量。例如:

struct{

intnum;charname[20];charsex;floatscore;}boy1,boy2;

表示結(jié)構(gòu)變量成員的一般形式是:結(jié)構(gòu)變量名.成員名例如:boy1.num即第一個(gè)人的學(xué)號(hào);boy2.sex即第二個(gè)人的性別。如果成員本身又是一個(gè)結(jié)構(gòu)則必須逐級(jí)找到最低級(jí)的成員才能使用。例如:boy1.birthday.month即第一個(gè)人出生的月份成員可以在程序中單獨(dú)使用,與普通變量完全相同。(3)結(jié)構(gòu)變量的賦值

前面已經(jīng)介紹,結(jié)構(gòu)變量的賦值就是給各成員賦值。可用輸入語句或賦值語句來完成。(4)結(jié)構(gòu)變量的初始化

如果結(jié)構(gòu)變量是全局變量或?yàn)殪o態(tài)變量,則可對(duì)它作初始化賦值。對(duì)局部或自動(dòng)結(jié)構(gòu)變量不能作初始化賦值。2.聯(lián)合

“聯(lián)合”與“結(jié)構(gòu)”有一些相似之處。但兩者有本質(zhì)上的不同。在結(jié)構(gòu)中各成員有各自的內(nèi)存空間,一個(gè)結(jié)構(gòu)變量的總長(zhǎng)度是各成員長(zhǎng)度之和。而在“聯(lián)合”中,各成員共享一段內(nèi)存空間,一個(gè)聯(lián)合變量的長(zhǎng)度等于各成員中最長(zhǎng)的長(zhǎng)度。應(yīng)該說明的是,這里所謂的共享不是指把多個(gè)成員同時(shí)裝入一個(gè)聯(lián)合變量?jī)?nèi),而是指該聯(lián)合變量可被賦予任一成員值,但每次只能賦一種值,賦入新值則沖去舊值。如前面介紹的“單位”變量,如定義為一個(gè)可裝入“班級(jí)”或“教研室”的聯(lián)合后,就允許賦予整型值(班級(jí))或字符串(教研室)。要么賦予整型值,要么賦予字符串,不能把兩者同時(shí)賦予它。聯(lián)合類型的定義和聯(lián)合變量的說明一個(gè)聯(lián)合類型必須經(jīng)過定義之后,才能把變量說明為該聯(lián)合類型。(1)聯(lián)合的定義

定義一個(gè)聯(lián)合類型的一般形式為:union聯(lián)合名{成員表;};成員表中含有若干成員,成員的一般形式為:類型說明符成員名。成員名的命名應(yīng)符合標(biāo)識(shí)符的規(guī)定。例如:unionperdata{

intclass;charoffice[10];};

定義了一個(gè)名為perdata的聯(lián)合類型,它含有兩個(gè)成員,一個(gè)為整型,成員名為class;另一個(gè)為字符數(shù)組,數(shù)組名為office。聯(lián)合定義之后,即可進(jìn)行聯(lián)合變量說明,被說明為perdata類型的變量,可以存放整型量class或存放字符數(shù)組office。(2)聯(lián)合變量的說明

聯(lián)合變量的說明和結(jié)構(gòu)變量的說明方式相同,也有三種形式。即先定義,再說明;定義同時(shí)說明和直接說明。以perdata類型為例,說明如下:

unionperdata

{

intclass;

charofficae[10];

};

unionperdataa,b;/*說明a,b為perdata類型*/

或者可同時(shí)說明為:

unionperdata

{

intclass;

charoffice[10];

}a,b;

或直接說明為:

union

{

intclass;

charoffice[10];

}a,b;

經(jīng)說明后的a,b變量均為perdata類型。a,b變量的長(zhǎng)度應(yīng)等于perdata

的成員中最長(zhǎng)的長(zhǎng)度,即等于office數(shù)組的長(zhǎng)度,共10個(gè)字節(jié)。a,b變量如賦予整型值時(shí),只使用了2個(gè)字節(jié),而賦予字符數(shù)組時(shí),可用10個(gè)字節(jié)。(3)聯(lián)合變量的賦值和使用

對(duì)聯(lián)合變量的賦值,使用都只能是對(duì)變量的成員進(jìn)行。聯(lián)合變量的成員表示為:聯(lián)合變量名.成員名例如,a被說明為perdata類型的變量之后,可使用a.class和a.office。不允許只用聯(lián)合變量名作賦值或其他操作。也不允許對(duì)聯(lián)合變量作初始化賦值,賦值只能在程序中進(jìn)行。還要再強(qiáng)調(diào)說明的是,一個(gè)聯(lián)合變量,每次只能賦予一個(gè)成員值。換句話說,一個(gè)聯(lián)合變量的值就是聯(lián)合變量的某一個(gè)成員值。6.1.7枚舉和位運(yùn)算

1.枚舉

在實(shí)際問題中,有些變量的取值被限定在一個(gè)有限的范圍內(nèi)。例如,一個(gè)星期內(nèi)只有七天,一年只有十二個(gè)月,一個(gè)班每周有六門課程等等。如果把這些量說明為整型,字符型或其他類型顯然是不妥當(dāng)?shù)?。為此,C語言提供了一種稱為“枚舉”的類型。在“枚舉”類型的定義中列舉出所有可能的取值,被說明為該“枚舉”類型的變量取值不能超過定義的范圍。應(yīng)該說明的是,枚舉類型是一種基本數(shù)據(jù)類型,而不是一種構(gòu)造類型,因?yàn)樗荒茉俜纸鉃槿魏位绢愋?。?)枚舉類型的定義和枚舉變量的說明

a.枚舉的定義

枚舉類型定義的一般形式為:

enum

枚舉名{枚舉值表};在枚舉值表中應(yīng)羅列出所有可用值。這些值也稱為枚舉元素。例如:

enumweekday{sun,mou,tue,wed,thu,fri,sat};

該枚舉名為weekday,枚舉值共有7個(gè),即一周中的七天。凡被說明為weekday類型變量的取值只能是七天中的某一天。b.枚舉變量的說明

如同結(jié)構(gòu)和聯(lián)合一樣,枚舉變量也可用不同的方式說明,即先定義后說明,同時(shí)定義說明或直接說明。設(shè)有變量a,b,c被說明為上述的weekday,可采用下述任一種方式:

enumweekday{......};

enumweekdaya,b,c;或者為:

enumweekday{......}a,b,c;或者為:

enum{......}a,b,c;(2)枚舉類型變量的賦值和使用

枚舉類型在使用中有以下規(guī)定:a.枚舉值是常量,不是變量。不能在程序中用賦值語句再對(duì)它賦值。例如對(duì)枚舉weekday的元素再作以下賦值:sun=5;mon=2;sun=mon;都是錯(cuò)誤的。b.枚舉元素本身由系統(tǒng)定義了一個(gè)表示序號(hào)的數(shù)值,從0開始順序定義為0,1,2,…。如在weekday中,sun值為0,mon值為1,…,sat值為6。c.只能把枚舉值賦予枚舉變量,不能把元素的數(shù)值直接賦予枚舉變量。如:a=sum;b=mon;是正確的。而:a=0;b=1;是錯(cuò)誤的。如一定要把數(shù)值賦予枚舉變量,則必須用強(qiáng)制類型轉(zhuǎn)換,如:a=(enumweekday)2;其意義是將順序號(hào)為2的枚舉元素賦予枚舉變量a,相當(dāng)于:a=tue;還應(yīng)該說明的是枚舉元素不是字符常量也不是字符串常量,使用時(shí)不要加單、雙引號(hào)。2.位運(yùn)算

前面介紹的各種運(yùn)算都是以字節(jié)作為最基本位進(jìn)行的。但在很多系統(tǒng)程序中常要求在位(bit)一級(jí)進(jìn)行運(yùn)算或處理。C語言提供了位運(yùn)算的功能,這使得C語言也能像匯編語言一樣用來編寫系統(tǒng)程序。位運(yùn)算符C語言提供了六種位運(yùn)算符: &按位與 |按位或 ^按位異或 ~取反 <<左移 >>右移(1)按位與運(yùn)算

按位與運(yùn)算符“&”是雙目運(yùn)算符。其功能是參與運(yùn)算的兩數(shù)各對(duì)應(yīng)的二進(jìn)位相與。只有對(duì)應(yīng)的兩個(gè)二進(jìn)位均為1時(shí),結(jié)果位才為1,否則為0。參與運(yùn)算的數(shù)以補(bǔ)碼方式出現(xiàn)。例如,9&5可寫算式如下:00001001(9的二進(jìn)制補(bǔ)碼)&00000101(5的二進(jìn)制補(bǔ)碼)=00000001(1的二進(jìn)制補(bǔ)碼)可見9&5=1。按位與運(yùn)算通常用來對(duì)某些位清零或保留某些位。例如把a(bǔ)的高八位清零,保留低八位,可作a&255運(yùn)算(255的二進(jìn)制數(shù)為0000000011111111)。(2)按位或運(yùn)算

按位或運(yùn)算符“|”是雙目運(yùn)算符。其功能是參與運(yùn)算的兩數(shù)各對(duì)應(yīng)的二進(jìn)位相或。只要對(duì)應(yīng)的二個(gè)二進(jìn)位有一個(gè)為1時(shí),結(jié)果位就為1。參與運(yùn)算的兩個(gè)數(shù)均以補(bǔ)碼出現(xiàn)。例如,9|5可寫算式如下:00001001|00000101=00001101(十進(jìn)制為13)可見9|5=13(3)按位異或運(yùn)算

按位異或運(yùn)算符“^”是雙目運(yùn)算符。其功能是參與運(yùn)算的兩數(shù)各對(duì)應(yīng)的二進(jìn)位相異或,當(dāng)兩對(duì)應(yīng)的二進(jìn)位相異時(shí),結(jié)果為1。參與運(yùn)算數(shù)仍以補(bǔ)碼出現(xiàn),例如,9^5可寫成算式如下:00001001^00000101=00001100(十進(jìn)制為12)(4)求反運(yùn)算

求反運(yùn)算符~為單目運(yùn)算符,具有右結(jié)合性。其功能是對(duì)參與運(yùn)算的數(shù)的各二進(jìn)位按位求反。例如,~9的運(yùn)算為:~(0000000000001001)結(jié)果為:1111111111110110(5)左移運(yùn)算

左移運(yùn)算符“<<”是雙目運(yùn)算符。其功能把“<<”左邊的運(yùn)算數(shù)的各二進(jìn)位全部左移若干位,由“<<”右邊的數(shù)指定移動(dòng)的位數(shù),高位丟棄,低位補(bǔ)0。例如:a<<4指把a(bǔ)的各二進(jìn)位向左移動(dòng)4位。如a=00000011(十進(jìn)制3),左移4位后為00110000(十進(jìn)制48)。(6)右移運(yùn)算

右移運(yùn)算符“>>”是雙目運(yùn)算符。其功能是把“>>”左邊的運(yùn)算數(shù)的各二進(jìn)位全部右移若干位,“>>”右邊的數(shù)指定移動(dòng)的位數(shù)。例如:設(shè)a=15,a>>2表示把000001111右移為00000011(十進(jìn)制3)。應(yīng)該說明的是,對(duì)于有符號(hào)數(shù),在右移時(shí),符號(hào)位將隨同移動(dòng)。當(dāng)為正數(shù)時(shí),最高位補(bǔ)0,而為負(fù)數(shù)時(shí),符號(hào)位為1,最高位是補(bǔ)0或是補(bǔ)1取決于編譯系統(tǒng)的規(guī)定。3.位域

有些信息在存儲(chǔ)時(shí),并不需要占用一個(gè)完整的字節(jié),而只需占幾個(gè)或一個(gè)二進(jìn)制位。例如,在存放一個(gè)開關(guān)量時(shí),只有0和1兩種狀態(tài),用一位二進(jìn)位即可。為了節(jié)省存儲(chǔ)空間,并使處理簡(jiǎn)便,C語言又提供了一種數(shù)據(jù)結(jié)構(gòu),稱為“位域”或“位段”。所謂“位域”是把一個(gè)字節(jié)中的二進(jìn)位劃分為幾個(gè)不同的區(qū)域,并說明每個(gè)區(qū)域的位數(shù)。每個(gè)域有一個(gè)域名,允許在程序中按域名進(jìn)行操作。這樣就可以把幾個(gè)不同的對(duì)象用一個(gè)字節(jié)的二進(jìn)制位域來表示。位域的定義和位域變量的說明位域定義與結(jié)構(gòu)定義類似,其形式為:

struct

位域結(jié)構(gòu)名{位域列表};其中位域列表的形式為:類型說明符位域名:位域長(zhǎng)度。例如:

struct

bs{

inta:8;

intb:2;

intc:6;};位域變量的說明與結(jié)構(gòu)變量說明的方式相同??刹捎孟榷x后說明,同時(shí)定義說明或者直接說明這三種方式。例如:

struct

bs{

inta:8;

intb:2;

intc:6;}data;

說明data為bs變量,共占兩個(gè)字節(jié)。其中,位域a占8位,位域b占2位,位域c占6位。對(duì)于位域的定義尚有以下幾點(diǎn)說明:(1)一個(gè)位域必須存儲(chǔ)在同一個(gè)字節(jié)中,不能跨兩個(gè)字節(jié)。如一個(gè)字節(jié)所剩空間不夠存放另一位域時(shí),從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:

struct

bs{unsigneda:4unsigned:0/*空域*/unsignedb:4/*從下一單元開始存放*/unsignedc:4}

在這個(gè)位域定義中,a占第一字節(jié)的4位,后4位填0表示不使用,b從第二字節(jié)開始,占用4位,c占用4位。

(2)由于位域不允許跨兩個(gè)字節(jié),因此位域的長(zhǎng)度不能大于一個(gè)字節(jié)的長(zhǎng)度,也就是說不能超過8位二進(jìn)位。(3)位域可以無位域名,這時(shí)它只用來作填充或調(diào)整位置。

無名的位域是不能使用的。例如:

structk{

inta:1

int:2/*該2位不能使用*/

intb:3

intc:2};

從以上分析可以看出,位域在本質(zhì)上就是一種結(jié)構(gòu)類型,不過其成員是按二進(jìn)位分配的。6.1.8預(yù)處理

以“#”號(hào)開頭的命令是預(yù)處理命令。如包含命令#include,宏定義命令#define等。在源程序中這些命令都放在函數(shù)之外,而且一般都放在源文件的前面,它們稱為預(yù)處理部分。所謂預(yù)處理是指在進(jìn)行編譯的第一遍掃描(詞法掃描和語法分析)之前所作的工作。預(yù)處理是C語言的一個(gè)重要功能,它由預(yù)處理程序負(fù)責(zé)完成。當(dāng)對(duì)一個(gè)源文件進(jìn)行編譯時(shí),系統(tǒng)將自動(dòng)引用預(yù)處理程序?qū)υ闯绦蛑械念A(yù)處理部分作處理,處理完畢自動(dòng)進(jìn)入對(duì)源程序的編譯。C語言提供了多種預(yù)處理功能,如宏定義、文件包含、條件編譯等。合理地使用預(yù)處理功能編寫的程序便于閱讀、修改、移植和調(diào)試,也有利于模塊化程序設(shè)計(jì)。下面介紹常用的幾種預(yù)處理功能。1.宏定義

在C語言源程序中允許用一個(gè)標(biāo)識(shí)符來表示一個(gè)字符串,稱為“宏”。被定義為“宏”的標(biāo)識(shí)符稱為“宏名”。在編譯預(yù)處理時(shí),對(duì)程序中所有出現(xiàn)的“宏名”,都用宏定義中的字符串去代換,這稱為“宏代換”或“宏展開”。宏定義是由源程序中的宏定義命令完成的。宏代換是由預(yù)處理程序自動(dòng)完成的。在C語言中,“宏”分為有參數(shù)和無參數(shù)兩種。下面分別討論這兩種“宏”的定義和調(diào)用。無參宏定義:無參宏的宏名后不帶參數(shù)。其定義的一般形式為: #define標(biāo)識(shí)符字符串其中的“#”表示這是一條預(yù)處理命令。凡是以“#”開頭的均為預(yù)處理命令?!癲efine”為宏定義命令?!皹?biāo)識(shí)符”為所定義的宏名?!白址笨梢允浅?shù)、表達(dá)式、格式串等。符號(hào)常量的定義就是一種無參宏定義。此外,常對(duì)程序中反復(fù)使用的表達(dá)式進(jìn)行宏定義。例如:#defineM(y*y+3*y)定義M表達(dá)式(y*y+3*y)。在編寫源程序時(shí),所有的(y*y+3*y)都可由M代替,而對(duì)源程序作編譯時(shí),將先由預(yù)處理程序進(jìn)行宏代換,即用(y*y+3*y)表達(dá)式去置換所有的宏名M,然后再進(jìn)行編譯。對(duì)于宏定義還要說明以下幾點(diǎn):

1)宏定義是用宏名來表示一個(gè)字符串,在宏展開時(shí)又以該字符串取代宏名,這只是一種簡(jiǎn)單的代換,字符串中可以含任何字符,可以是常數(shù),也可以是表達(dá)式,預(yù)處理程序?qū)λ蛔魅魏螜z查。如有錯(cuò)誤,只能在編譯已被宏展開后的源程序時(shí)發(fā)現(xiàn)。

2)宏定義不是說明或語句,在行末不加分號(hào)。宏定義必須寫在函數(shù)之外,其作用域?yàn)楹甓x命令起到源程序結(jié)束。如要終止其作用域可使用#undef命令,例如:#definePI3.14159。

3)宏名在源程序中若用引號(hào)括起來,則預(yù)處理程序不對(duì)其作宏代換。宏定義允許嵌套,在宏定義的字符串中可以使用已經(jīng)定義的宏名。在宏展開時(shí)由預(yù)處理程序?qū)訉哟鷵Q。習(xí)慣上宏名用大寫字母表示,以便于與變量區(qū)別。但也允許用小寫字母。可用宏定義表示數(shù)據(jù)類型,使書寫方便。例如:#defineSTUstructstudent

在程序中可用STU作變量說明:STUbody[5],*p;#defineINTEGERint

在程序中即可用INTEGER作整型變量說明:INTEGERa,b;

4)應(yīng)注意用宏定義表示數(shù)據(jù)類型和用typedef定義數(shù)據(jù)說明符的區(qū)別。宏定義只是簡(jiǎn)單的字符串代換,是在預(yù)處理完成的,而typedef是在編譯時(shí)處理的,它不是作簡(jiǎn)單的代換,而是對(duì)類型說明符重新命名。被命名的標(biāo)識(shí)符具有類型定義說明的功能。請(qǐng)看下面的例子:#definePIN1int*typedef(int*)PIN2;

從形式上看這兩者相似,但在實(shí)際使用中卻不相同。下面用PIN1,PIN2說明變量時(shí)就可以看出它們的區(qū)別:PIN1a,b;

在宏代換后變成int*a,b;表示a是指向整型的指針變量,而b是整型變量。然而:PIN2a,b;表示a,b都是指向整型的指針變量。因?yàn)镻IN2是一個(gè)類型說明符。由這個(gè)例子可見,宏定義雖然也可表示數(shù)據(jù)類型,但畢竟是作字符代換,使用時(shí)要分外小心,以免出錯(cuò)。帶參宏定義:

C語言允許宏帶有參數(shù)。在宏定義中的參數(shù)稱為形式參數(shù),在宏調(diào)用中的參數(shù)稱為實(shí)際參數(shù)。對(duì)帶參數(shù)的宏,在調(diào)用中,不僅要宏展開,而且要用實(shí)參去代換形參。帶參宏定義的一般形式為:#define宏名(形參表)字符串在字符串中含有各個(gè)形參。帶參宏調(diào)用的一般形式為:宏名(實(shí)參表);參宏定義中,宏名和形參表之間不能有空格出現(xiàn)。例如把:#defineMAX(a,b)(a>b)?a:b寫為:#defineMAX(a,b)(a>b)?a:b

將被認(rèn)為是無參宏定義,宏名MAX代表字符串(a,b)(a>b)?a:b。宏展開時(shí),宏調(diào)用語句:max=MAX(x,y);將變?yōu)椋簃ax=(a,b)(a>b)?a:b(x,y);這顯然是錯(cuò)誤的。在帶參宏定義中,形式參數(shù)不分配內(nèi)存單元,因此不必作類型定義。而宏調(diào)用中的實(shí)參有具體的值。要用它們?nèi)ゴ鷵Q形參,因此必須作類型說明。這是與函數(shù)中的情況不同的。在函數(shù)中,形參和實(shí)參是兩個(gè)不同的量,各有自己的作用域,調(diào)用時(shí)要把實(shí)參值賦予形參,進(jìn)行“值傳遞”。而在帶參宏中,只是符號(hào)代換,不存在值傳遞的問題。在宏定義中的形參是標(biāo)識(shí)符,而宏調(diào)用中的實(shí)參可以是表達(dá)式。在宏定義中,字符串內(nèi)的形參通常要用括號(hào)括起來以避免出錯(cuò)。帶參的宏和帶參函數(shù)很相似,但有本質(zhì)上的不同,除上面已談到的各點(diǎn)外,把同一表達(dá)式用函數(shù)處理與用宏處理兩者的結(jié)果有可能是不同的。宏定義也可用來定義多個(gè)語句,在宏調(diào)用時(shí),把這些語句又代換到源程序內(nèi)。2.文件包含

文件包含是C預(yù)處理程序的另一個(gè)重要功能。文件包含命令行的一般形式為:#include"文件名"例如:#include"stdio.h"#include"math.h"

文件包含命令的功能是把指定的文件插入該命令行位置取代該命令行,從而把指定的文件和當(dāng)前的源程序文件連成一個(gè)源文件。在程序設(shè)計(jì)中,文件包含是很有用的。一個(gè)大的程序可以分為多個(gè)模塊,由多個(gè)程序員分別編程。有些公用的符號(hào)常量或宏定義等可單獨(dú)組成一個(gè)文件,在其他文件的開頭用包含命令包含該文件即可使用。這樣,可避免在每個(gè)文件開頭都去書寫那些公用量,從而節(jié)省時(shí)間,并減少出錯(cuò)。對(duì)文件包含命令還要說明以下幾點(diǎn):(1)包含命令中的文件名可以用雙引號(hào)括起來,也可以用尖括號(hào)括起來。例如以下寫法都是允許的:#include"stdio.h"#include<math.h>

但是這兩種形式是有區(qū)別的:使用尖括號(hào)表示在包含文件目錄中去查找(包含目錄是由用戶在設(shè)置環(huán)境時(shí)設(shè)置的),而不在源文件目錄去查找;使用雙引號(hào)則表示首先在當(dāng)前的源文件目錄中查找,若未找到才到包含目錄中去查找。用戶編程時(shí)可根據(jù)自己文件所在的目錄來選擇某一種命令形式。(2)一個(gè)include命令只能指定一個(gè)被包含文件,若有多個(gè)文件要包含,則需用多個(gè)include命令。(3)文件包含允許嵌套,即在一個(gè)被包含的文件中又可以包含另一個(gè)文件。3.條件編譯預(yù)處理程序提供了條件編譯的功能??梢园床煌臈l件去編譯不同的程序部分,因而產(chǎn)生不同的目標(biāo)代碼文件。這對(duì)于程序的移植和調(diào)試是很有用的。條件編譯有三種形式,下面分別介紹:(1)第一種形式:#ifdef

標(biāo)識(shí)符程序段1#else程序段2#endif

它的功能是,如果標(biāo)識(shí)符已被#define命令定義過,則對(duì)程序段1進(jìn)行編譯;否則對(duì)程序段2進(jìn)行編譯。如果沒有程序段2(它為空),本格式中的#else可以沒有。(2)第二種形式:#ifndef

標(biāo)識(shí)符程序段1#else程序段2#endif

與第一種形式的區(qū)別是將“ifdef”改為“ifndef”。它的功能是,如果標(biāo)識(shí)符未被#define命令定義過則對(duì)程序段1進(jìn)行編譯,否則對(duì)程序段2進(jìn)行編譯。這與第一種形式的功能正相反。(3)第三種形式:#if常量表達(dá)式程序段1#else程序段2#endif

它的功能是,如常量表達(dá)式的值為真(非0),則對(duì)程序段1進(jìn)行編譯,否則對(duì)程序段2進(jìn)行編譯。因此可以使程序在不同條件下,完成不同的功能。上面介紹的條件編譯當(dāng)然也可以用條件語句來實(shí)現(xiàn)。但是用條件語句將會(huì)對(duì)整個(gè)源程序進(jìn)行編譯,生成的目標(biāo)代碼程序很長(zhǎng),而采用條件編譯,則根據(jù)條件只編譯其中的程序段1或程序段2,生成的目標(biāo)程序較短。如果條件選擇的程序段很長(zhǎng),采用條件編譯的方法是十分必要的。6.2KeilC對(duì)ANSIC

的擴(kuò)展當(dāng)設(shè)計(jì)一個(gè)小的嵌入式系統(tǒng)時(shí)一般使用匯編語言。在很多工程中這是一個(gè)很好的方法,因?yàn)榇a一般都不長(zhǎng),而且都比較簡(jiǎn)單。使用匯編的麻煩在于它的可讀性和可維護(hù)性,代碼的可重用性也比較低。但是如果使用C語言的話可以很好地解決這些問題。因?yàn)镃語言有很好的結(jié)構(gòu)性和模塊化,更容易閱讀和維護(hù),用C語言編寫的程序有很好的可移植性。功能化的代碼能夠很方便地從一個(gè)工程移植到另一個(gè)工程,從而減少了開發(fā)時(shí)間。用C編寫程序比匯編更符合人們的思考習(xí)慣,開發(fā)者可以更專心地考慮算法而不是考慮一些細(xì)節(jié)問題,這樣就減少了開發(fā)和調(diào)試的時(shí)間。使用像C這樣的語言的程序員不必十分熟悉處理器的構(gòu)造。這意味著對(duì)新的處理器也能很快上手。不必知道處理器的具體內(nèi)部結(jié)構(gòu),使得用C編寫的程序比匯編程序有更好的可移植性。很多處理器支持C編譯器,所有這些并不說明匯編語言就沒了立足之地,很多系統(tǒng)特別是實(shí)時(shí)性較高的系統(tǒng)都是用C和匯編語言聯(lián)合編程。并且,當(dāng)對(duì)時(shí)鐘要求很嚴(yán)格時(shí),使用匯編語言成了唯一的方法。除此之外,包括硬件接口的操作都應(yīng)該用C來編程。C的特點(diǎn)就是可以使你盡量少地對(duì)硬件進(jìn)行操作,是一種功能性和結(jié)構(gòu)性很強(qiáng)的語言。深入理解并應(yīng)用C51對(duì)標(biāo)準(zhǔn)ANSIC的擴(kuò)展是學(xué)習(xí)C51的關(guān)鍵之一。因?yàn)榇蠖鄶?shù)擴(kuò)展功能都是直接針對(duì)8051系列CPU硬件的。6.2.1KeilC51擴(kuò)展關(guān)鍵字

C51版本有以下擴(kuò)展關(guān)鍵字(共19個(gè)):_at_sbit

sfrbitsfr16idata

bdata

xdata

pdatadatacodealiensmallcompactlargeusingreentrantinterrupt _task_1.內(nèi)存區(qū)域(MemoryAreas):

(1)PragramArea:由Code說明可有多達(dá)64kB的程序存儲(chǔ)器

(2)InternalDataMemory:

內(nèi)部數(shù)據(jù)存儲(chǔ)器可用以下關(guān)鍵字說明:data:直接尋址區(qū),為內(nèi)部RAM的低128字節(jié)00H~7FH

idata:間接尋址區(qū),包括整個(gè)內(nèi)部RAM區(qū)00H~0FFH

bdata:可位尋址區(qū),20H~2FH(3)ExternalDataMemory

外部RAM視使用情況可由以下關(guān)鍵字標(biāo)識(shí):

xdata:可指定多達(dá)64KB的外部直接尋址區(qū),地址范圍0000H~0FFFFH

pdata:能訪問1頁(256Bytes)的外部RAM,主要用于緊湊模式(CompactModel)。

(4)SpeciacFunctionRegisterMemorySTC12C5410AD單片機(jī)提供128B的SFR尋址區(qū),可進(jìn)行位尋址、字節(jié)尋址或字尋址,用以控制定時(shí)器、計(jì)數(shù)器、串口、I/O及其他部件,可由以下幾種關(guān)鍵字說明:

sfr:字節(jié)尋址,如sfrP0=0x80;為PO口地址為80H,“=”后00H~0FFH之間的常數(shù)。sfr16:字尋址,如sfr16T2=0xcc;指定Timer2口地址T2L=0xccT2H=0xCD。

sbit:位尋址,如sbitEA=0xAF;指定第0xAF位為EA,即中斷允許。還可以有如下定義方法:

sbit0V=PSW^2;(定義0V為PSW的第2位)

sbit0V=0XDO^2;(同上)或bit0V-=0xD2(同上)。2._at_關(guān)鍵字若要實(shí)現(xiàn)變量的絕對(duì)定位(稱為絕對(duì)變量),可以直接在數(shù)據(jù)定義后加上“_at_常數(shù)地址”即可,但是注意:(1)絕對(duì)變量不能被初使化;(2)bit型函數(shù)及變量不能用_at_指定。例如:unsignedcharadcdata

idata_at_0x40;//指定adcdata變量在40H處unsignedcharbuffer[20]xdata_at_0x0010;//指定buffer數(shù)組從外部RAM的0010H單元開始3.存儲(chǔ)模式存儲(chǔ)模式?jīng)Q定了沒有明確指定存儲(chǔ)類型的變量,函數(shù)參數(shù)等的缺省存儲(chǔ)區(qū)域,共三種:1.Small模式所有缺省變量參數(shù)均裝入內(nèi)部RAM,優(yōu)點(diǎn)是訪問速度快,缺點(diǎn)是空間有限,只適用于小程序。2.Compact模式所有缺省變量均位于外部RAM區(qū)的一頁(256Bytes),具體哪一頁可由P2口指定,在STARTUP.A51文件中說明,也可用pdata指定,優(yōu)點(diǎn)是空間較Small為寬裕速度較Small慢,較large要快,是一種中間狀態(tài)。3.large模式所有缺省變量可放在多達(dá)64KB的外部RAM區(qū),優(yōu)點(diǎn)是空間大,可存變量多,缺點(diǎn)是速度較慢。提示:存儲(chǔ)模式在C51編譯器選項(xiàng)中選擇。存儲(chǔ)類型聲明:變量或參數(shù)的存儲(chǔ)類型可由存儲(chǔ)模式指定缺省類型,也可由關(guān)鍵字直接聲明指定。各類型分別用:code,data,idata,xdata,pdata說明,例:datauar1;charcodearray[]=“hello!”;unsignedcharxdataarr[10][4][4];4變量或數(shù)據(jù)類型

C51提供以下幾種擴(kuò)展數(shù)據(jù)類型:bit位變量值為0或1

sbit

從字節(jié)中定義的位變量0或1

sfr

sfr字節(jié)地址0~255sfr16sfr字地址0~65535其余數(shù)據(jù)類型如:char,enum,short,int,long,float等與ANSIC相同。(1)bit型變量bit型變量可用變量類型,函數(shù)聲明、函數(shù)返回值等,存儲(chǔ)于內(nèi)部RAM20H~2FH。

注意:(1)用#pragmadisable說明函數(shù)和用“usigned”指定的函數(shù),不能返回bit值。(2)一個(gè)bit變量不能聲明為指針,如bit*ptr;是錯(cuò)誤的(3)不能有bit數(shù)組如:bitarr[5];錯(cuò)誤。

(2)可位尋址區(qū)說明可作如下定義:

intdatai;charbdataarr[3],

然后:

sbitbit0=i^0;

sbitbit15=i^15;

sbitarr07=arr[0]^7;

sbitarr15=arr[1]^76.2.2KeilC51指針

C51支持一般指針(GenericPointer)和存儲(chǔ)器指針(Memory_SpecificPointer)。一般指針的聲明和使用均與標(biāo)準(zhǔn)C相同,不過同時(shí)還可以說明指針的存儲(chǔ)類型,例如:long*state;為一個(gè)指向long型整數(shù)的指針,而state本身則依存儲(chǔ)模式存放。char*dataptr;

ptr為一個(gè)指向char數(shù)據(jù)的指針,而ptr本身放于外部RAM區(qū)。以上的long,char等指針指向的數(shù)據(jù)可存放于任何存儲(chǔ)器中。一般指針本身用3個(gè)字節(jié)存放,分別為存儲(chǔ)器類型,高位偏移,低位偏移量?;诖鎯?chǔ)器的指針說明時(shí)即指定了存儲(chǔ)類型,例如:chardata*str;str指向data區(qū)中char型數(shù)據(jù)

int

xdata*pow;pow指向外部RAM的int型整數(shù)這種指針存放時(shí),只需一個(gè)字節(jié)或2個(gè)字節(jié)就夠了,因?yàn)橹恍璐娣牌屏?。指針轉(zhuǎn)換即指針在上兩種類型之間轉(zhuǎn)化:當(dāng)基于存儲(chǔ)器的指針作為一個(gè)實(shí)參傳遞給需要一般指針的函數(shù)時(shí),指針自動(dòng)轉(zhuǎn)化。如果不說明外部函數(shù)原形,基于存儲(chǔ)器的指針自動(dòng)轉(zhuǎn)化為一般指針,將導(dǎo)致錯(cuò)誤,因而請(qǐng)用“#include”說明所有函數(shù)原形??梢詮?qiáng)行改變指針類型。6.2.3KeilC51函數(shù)

C51函數(shù)聲明對(duì)ANSIC作了擴(kuò)展,具體包括:1.中斷函數(shù)聲明:

中斷函數(shù)通過使用interrupt關(guān)鍵字和中斷號(hào)(0到31)來聲明。中斷號(hào)告訴編譯器中斷程序的入口地址,中斷號(hào)對(duì)應(yīng)著IE寄存器中的使能位。IE寄存器中的第0位對(duì)應(yīng)著外部中斷0,相應(yīng)的外部中斷0的中斷號(hào)是0;IE寄存器中的第1位對(duì)應(yīng)定時(shí)器T0,相應(yīng)的定時(shí)器T0的中斷號(hào)是1,依此類推。舉例來說,中斷聲明方法如下:voidUART_ISR(void)interrupt4[using1]{/*ISR*/}

上述代碼聲明了串行通信中斷服務(wù)函數(shù)。其中,interrupt4說明采用了第四個(gè)中斷向量,using1指明采用工作寄存器區(qū)1區(qū)。其他中斷函數(shù)的定義與此類似。為提高代碼的容錯(cuò)能力,在沒用到的中斷入口處生成reti語句,定義沒用到的中斷。voidX0_ISR(void)interrupt0{}//外部中斷0中斷函數(shù)voidT0_ISR(void)interrupt1{}//定時(shí)器T0中斷函數(shù)voidX1_ISR(void)interrupt2{}//外部中斷1中斷函數(shù)voidT1_ISR(void)interrupt3{}//定時(shí)器T1中斷函數(shù)voidUART_ISR(void)interrupt4{}//串行通信中斷函數(shù)voidADCSPI_ISR(void)interrupt5{}//ADC和SPI中斷函數(shù)voidPCA_ISR(void)interrupt6{}//PCA中斷函數(shù)2.指定工作寄存器區(qū)指定工作寄存器區(qū)由usingx聲明(x=0~3),例如:UnsignedcharG

溫馨提示

  • 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)論