《C語言程序設(shè)計(jì)基礎(chǔ)》課件第10章_第1頁
《C語言程序設(shè)計(jì)基礎(chǔ)》課件第10章_第2頁
《C語言程序設(shè)計(jì)基礎(chǔ)》課件第10章_第3頁
《C語言程序設(shè)計(jì)基礎(chǔ)》課件第10章_第4頁
《C語言程序設(shè)計(jì)基礎(chǔ)》課件第10章_第5頁
已閱讀5頁,還剩47頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第10章

編譯預(yù)處理與位運(yùn)算10.1編譯預(yù)處理10.2位運(yùn)算實(shí)訓(xùn)任務(wù)十九

熟悉C語言中的編譯預(yù)處理命令和位運(yùn)算功能實(shí)訓(xùn)任務(wù)二十

學(xué)習(xí)編譯預(yù)處理和位運(yùn)算應(yīng)用編程

10.1編譯預(yù)處理

如何使用C語言系統(tǒng)提供的功能資源,方便用戶編程?

在前面各章中,已多次使用過以“#”開頭的預(yù)處理命令,如包含命令#include,宏定義命令#define等。在源程序中這些命令都放在主函數(shù)之外,而且一般都放在源文件的開始位置,稱為預(yù)處理部分。

所謂預(yù)處理是指編譯系統(tǒng)在對一個(gè)源程序進(jìn)行編譯之前,先對程序某些特殊命令進(jìn)行處理,再將處理結(jié)果和源程序一起編譯生成目標(biāo)程序。預(yù)處理是C語言系統(tǒng)的一個(gè)重要功能,它由預(yù)處理程序來完成。當(dāng)對一個(gè)源文件進(jìn)行編譯時(shí),系統(tǒng)將自動引用預(yù)處理程序?qū)υ闯绦蛑械念A(yù)處理部分作處理,處理完畢自動進(jìn)入源程序的編譯。合理使用預(yù)處理功能可方便程序的編寫、閱讀、修改、移植和調(diào)試,能提高編程的效率,也有利于模塊化程序設(shè)計(jì)。

C語言系統(tǒng)提供了多種預(yù)處理功能,如宏定義、文件包含、條件編譯等。使用各種編譯預(yù)處理命令時(shí)應(yīng)注意以下幾點(diǎn):

(1)編譯預(yù)處理命令不是C語言的語句,一般放在程序的開頭,但也可以根據(jù)需要放在程序中間或程序末尾等位置。

(2)編譯預(yù)處理命令的書寫均以“#”開頭,因?yàn)椴皇荂語言的語句,故末尾不加分號。

(3)一行只能書寫一條編譯預(yù)處理命令。

(4)編譯預(yù)處理命令多用以實(shí)現(xiàn)一種簡單替換功能,編譯時(shí)系統(tǒng)不進(jìn)行語法檢查。

10.1.1宏定義

1.無參宏定義

無參宏定義的一般形式為

#define標(biāo)識符

源字符串

其中,“標(biāo)識符”為所定義的宏名?!霸醋址笨梢允浅?shù)、表達(dá)式、格式串等。例如:

#definePI3.1415926

經(jīng)此定義,程序就可以用PI代表3.1415926,顯然能簡化書寫,提高符號的明晰性。預(yù)編譯時(shí)又要將源程序中所有宏名PI出現(xiàn)的位置用3.1415926來替換。關(guān)于宏定義使用的幾點(diǎn)說明:

(1)宏名一般用大寫字母表示,以便與普通變量相區(qū)別。

(2)?#與define間一般不留空格,宏名兩側(cè)必須至少用一個(gè)(可以多個(gè))空格分隔。

(3)宏定義用宏名代替一個(gè)字符串,并不管它的數(shù)據(jù)類型是什么,也不管詞法和語法是否正確,只作簡單的替換。

(4)?#define命令定義的宏名作用范圍是從定義命令開始直到源程序文件結(jié)束,一般情況下,#define總是定義在文件開頭,不能在函數(shù)內(nèi)。還可以在程序中通過#undef提前終止宏名的作用域。例如:

(5)宏定義中,宏名還可以出現(xiàn)在被定義的字符串中,但還原時(shí)又分層置換。例如:

#definePI3.1415926

#defineSPI*y*y(PI是已定義的宏名)

此時(shí),S表示的串是3.1415926*y*y。

(6)宏定義是專用于預(yù)處理的一個(gè)名詞,它與變量定義的含義不同,只是在編譯時(shí)進(jìn)行的字符串簡單替換,不分配內(nèi)存空間。它為編程提供方便,能提高程序的通用性。

2.帶參宏定義

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

帶參宏定義的一般形式為

#define宏名(形參表)字符串

在字符串中含有形參。

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

宏名(實(shí)參表);

關(guān)于帶參宏定義的幾點(diǎn)說明:

(1)在帶參宏定義中,形式參數(shù)不分配內(nèi)存單元,因此不必作類型定義。而宏調(diào)用中的實(shí)參有具體的值,要用它們代換形參,因此必須作類型說明。這是與函數(shù)中的情況不同的。在函數(shù)中,形參和實(shí)參是兩個(gè)不同的量,各有自己的作用域,調(diào)用時(shí)要把實(shí)參值賦予形參,進(jìn)行“值傳遞”。而在帶參宏中,只是符號代換,不存在值傳遞的問題。

(2)宏定義中的形參是標(biāo)識符,宏調(diào)用中的實(shí)參可以是表達(dá)式。

第1行為宏定義,形參為y。第8行宏調(diào)用中實(shí)參為a+1,是一個(gè)表達(dá)式。在宏展開時(shí),用a+1代換y,再用(y)*(y)代換SQR,預(yù)編譯處理后的語句是“q=(a+1)*(a+1);”。

這與函數(shù)的調(diào)用是不同的,函數(shù)調(diào)用時(shí)要把實(shí)參表達(dá)式的值求出來再賦予形參。而宏代換中對實(shí)參表達(dá)式不進(jìn)行計(jì)算,直接地照原樣代換。

(3)在宏定義中,字符串內(nèi)的形參通常要用括號括起來,以避免出錯(cuò)。上例中的宏定義(y)*(y)表達(dá)式的y都用括號括起來。如果去掉括號,把預(yù)處理命令改為

#defineSQR(y)y*y

宏代換后的語句是“q=a+1*a+1;”。顯然將出現(xiàn)結(jié)果錯(cuò)誤。

(4)函數(shù)調(diào)用和宏調(diào)用二者在形式上相似,但本質(zhì)上是完全不同的。宏定義也可用來定義多個(gè)語句,在宏調(diào)用時(shí),把這些語句又代換到源程序內(nèi)。

程序第1行為宏定義,用宏名SV表示4個(gè)賦值語句,4個(gè)形參分別為4個(gè)賦值符左部的變量。在宏調(diào)用時(shí),把4個(gè)語句展開并用實(shí)參代替形參,即SV(sa,sb,sc,vv)的位置用如下4個(gè)賦值語句來替換:

sa=l*w;sb=l*h;sc=w*h;vv=w*l*h;

10.1.2文件包含

文件包含預(yù)處理命令的一般形式為

#include"文件名"

#include<文件名>

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

#include"stdio.h"

#include"string.h"

#include"math.h"文件包含命令的功能是把指定的文件插入該命令行位置取代該命令行,作為本程序文件的組成部分。

在程序設(shè)計(jì)中,文件包含是很有用的。一個(gè)大的程序可以分為多個(gè)模塊,由多個(gè)程序員分別編程。有些公用的符號常量或宏定義等可單獨(dú)組成一個(gè)文件,在其他文件的開頭用包含命令包含該文件即可使用。這樣,可避免在每個(gè)文件開頭都去書寫那些公用量,從而節(jié)省時(shí)間,并減少出錯(cuò)。

關(guān)于文件包含命令使用的幾點(diǎn)說明:

(1)包含命令中的文件名可以用雙引號括起來,也可以用尖括號括起來,主要區(qū)別在于系統(tǒng)查找文件的路徑不同。使用尖括號表示在包含文件目錄中查找(包含目錄是由用戶在設(shè)置環(huán)境時(shí)設(shè)置的)而不在源文件目錄中查找;使用雙引號則表示首先在當(dāng)前的源文件目錄中查找,若未找到,再到包含目錄中查找。這種使用形式更加通用。用戶編程時(shí)可根據(jù)自己文件所在的目錄來選擇一種命令形式。

(2)一個(gè)include命令只能指定一個(gè)被包含文件,若有多個(gè)文件要包含,則需用多個(gè)include命令。文件包含允許嵌套,即在一個(gè)被包含的文件中又可以包含另一個(gè)文件。

10.1.3條件編譯

預(yù)處理程序提供了條件編譯的功能,可以按不同的條件編譯不同的程序部分,因而產(chǎn)生不同的目標(biāo)代碼文件。這對于程序的移植和調(diào)試是很有用的。條件編譯有三種形式。

它的功能是,如果標(biāo)識符已被#define命令定義過,則對程序段1進(jìn)行編譯,否則對程序段2進(jìn)行編譯。也可以寫為

#ifdef標(biāo)識符

程序段

#endif

如果標(biāo)識符已被#define命令定義過,則對程序段進(jìn)行編譯,否則不對程序段進(jìn)行編譯。

由于在程序的第17行插入了條件編譯預(yù)處理命令,因此要根據(jù)NUM是否被定義過,來決定編譯哪一個(gè)printf語句。而在程序的第2行已對NUM作過宏定義,因此應(yīng)編譯第1個(gè)printf語句,故運(yùn)行結(jié)果是輸出了學(xué)號和成績。

第二種形式:

#ifndef標(biāo)識符

程序段1

#else

程序段2

#endif

與第一種形式的區(qū)別是:將“ifdef”改為“ifndef”。它的功能是,如果標(biāo)識符未被#define命令定義過,則對程序段1進(jìn)行編譯,否則對程序段2進(jìn)行編譯。其編譯條件與第一種形式相反。

第三種形式:

#if常量表達(dá)式

程序段1

#else

程序段2

#endif

它的功能是,如常量表達(dá)式的值為真(非0),則對程序段1進(jìn)行編譯,否則對程序段2進(jìn)行編譯。因此可以使程序在不同條件下,完成不同的功能。

在程序第2行宏定義中,定義R為1,因此在條件編譯時(shí),常量表達(dá)式的值為真,故計(jì)算并輸出圓面積。

上面介紹的條件編譯當(dāng)然也可以用條件語句來實(shí)現(xiàn)。但是用條件語句將會對整個(gè)源程序進(jìn)行編譯,生成的目標(biāo)代碼程序比較長,而采用條件編譯,則根據(jù)條件只編譯其中的程序段1或程序段2,生成的目標(biāo)程序較短。如果條件選擇的程序段很長,采用條件編譯的方法是十分必要的。

10.2位

運(yùn)

何謂位運(yùn)算?C語言有哪些位運(yùn)算功能?

位運(yùn)算就是對二進(jìn)制數(shù)的按位運(yùn)算。這種運(yùn)算是在計(jì)算機(jī)的硬件級上常進(jìn)行的運(yùn)算。很多系統(tǒng)程序中常要求在位(bit)一級進(jìn)行運(yùn)算或處理。C語言提供了位運(yùn)算的功能,這使得C語言既具有其他高級語言的特點(diǎn),又具備低級程序設(shè)計(jì)語言的功能。位運(yùn)算只能對整型或字符型數(shù)據(jù)進(jìn)行,C語言中有六種位運(yùn)算符,它們的作用、結(jié)合方向和優(yōu)先級見表10.1。表10.1六種基本位運(yùn)算符10.2.1位運(yùn)算符

1.位“與”運(yùn)算

位“與”運(yùn)算的符號為“&”,是對兩個(gè)二進(jìn)制數(shù)按位進(jìn)行邏輯“與”運(yùn)算。只有兩個(gè)二進(jìn)制數(shù)的運(yùn)算位均為1時(shí),該位的運(yùn)算結(jié)果才為1,否則為0。

按位“與”運(yùn)算通常用來對某些位清0或保留某些位。例如把a(bǔ)的高八位清0,保留低八位,可作a=a&255運(yùn)算(255的二進(jìn)制數(shù)為0000000011111111)。

2.位“或”運(yùn)算

位“或”運(yùn)算的符號為“|”,是對兩個(gè)二進(jìn)制數(shù)按位進(jìn)行邏輯“或”運(yùn)算。只有兩個(gè)二進(jìn)制數(shù)的運(yùn)算位均為0時(shí),該位的運(yùn)算結(jié)果才為0,否則為1。

按位“或”運(yùn)算通常用來對某些位置1或保留某些位。例如a=a|1,使a的最低位置1。

3.位“異或”運(yùn)算

位“異或”運(yùn)算的符號為“∧”,是對兩個(gè)二進(jìn)制數(shù)按位進(jìn)行邏輯“異或”運(yùn)算。兩個(gè)二進(jìn)制數(shù)的對應(yīng)位相異時(shí),結(jié)果為1;相同時(shí),結(jié)果為0。

4.位“取反”運(yùn)算

位“求反”運(yùn)算的符號為“~”,是對一個(gè)二進(jìn)制數(shù)逐位取反,即原為1,取反為0;原為0,取反為1。

5.左移運(yùn)算

左移運(yùn)算的符號為“<<”,是把一個(gè)二進(jìn)制數(shù)左移指定的位數(shù)。左移時(shí),高位丟掉,低位補(bǔ)0。要左移的數(shù)據(jù)對象在運(yùn)算符左面,左移位數(shù)在運(yùn)算符右面。

6.右移運(yùn)算

右移運(yùn)算的符號為“>>”,是把一個(gè)二進(jìn)制數(shù)右移指定的位數(shù)。右移時(shí)高位補(bǔ)0,低位丟掉。要右移的數(shù)據(jù)對象在運(yùn)算符左面,右移位數(shù)在運(yùn)算符右面。

10.2.2位處理程序設(shè)計(jì)舉例

例10.5

輸入一個(gè)十六進(jìn)制數(shù)據(jù)和一個(gè)狀態(tài)數(shù)據(jù),檢測狀態(tài)數(shù)據(jù)的最低位是否為0,為0,則截取數(shù)據(jù)的4~7位輸出,為1則輸出“BUSY”。

編程思路:要檢測某一位是否為0,只要設(shè)置一個(gè)對應(yīng)位上為1,其他位上為0的二進(jìn)制數(shù),用這個(gè)二進(jìn)制數(shù)和被檢測的二進(jìn)制數(shù)進(jìn)行“與”運(yùn)算,結(jié)果為0,則被檢測位為0。要截取數(shù)據(jù)的4~7位,只要設(shè)置一個(gè)4~7位為1,其他位0的二進(jìn)制數(shù),與被截取的數(shù)據(jù)進(jìn)行“與”運(yùn)算,則數(shù)據(jù)的4~7位保留下來,其他數(shù)位均為0,然后右移4位,將保留數(shù)位移到最低位即可。

運(yùn)行結(jié)果:

分析:輸入十六進(jìn)制數(shù)B75D,截取內(nèi)部二進(jìn)制數(shù)的4~7位,對應(yīng)的十六進(jìn)制數(shù)應(yīng)該是5。輸入十六進(jìn)制狀態(tài)數(shù)據(jù)FFFE,對應(yīng)二進(jìn)制數(shù)的最低位是0,經(jīng)if語句判斷,輸出截取的數(shù)。

例10.6

將a右循環(huán)移位k位。如果a中有二進(jìn)制數(shù)1101111110101011,設(shè)右循環(huán)移位3位,則移位后的結(jié)果應(yīng)為0111101111110101。

編程思路:C語言中的移位運(yùn)算只能實(shí)現(xiàn)邏輯移位,不能實(shí)現(xiàn)循環(huán)移位,移位數(shù)據(jù)對象是變量。變量的值在計(jì)算機(jī)內(nèi)是以二進(jìn)制字符存儲的。要實(shí)現(xiàn)循環(huán)移位,必須采取一定算法。為滿足題目要求,設(shè)字長為16位,可采用以下步驟。

(1)將a的低16-k位先邏輯左移到b的高位端,低16-k位全補(bǔ)為0,可用下面語句來實(shí)現(xiàn):

b=a<<(16-k);

(2)將a邏輯右移k位,高k位補(bǔ)0,可用下面語句來實(shí)現(xiàn):

c=a>>k;

運(yùn)行結(jié)果:

分析:輸入移位數(shù)4,是對機(jī)內(nèi)二進(jìn)制數(shù)循環(huán)右移4位,對應(yīng)十六進(jìn)制數(shù)的一位。

10.2.3位段(位域)

如前所述,C語言的各種運(yùn)算都是以字作為最基本單位進(jìn)行的。但在某些特殊情況下,為節(jié)省存儲空間,簡化處理,允許信息存儲時(shí),可以不占用一個(gè)完整的字存儲單元,而只需占用幾個(gè)二進(jìn)制位。例如在存放一個(gè)開關(guān)量時(shí),只有0和1兩種狀態(tài),用一位二進(jìn)制位即可。為此,C語言又提供了一種數(shù)據(jù)結(jié)構(gòu),稱為“位段”或“位域”。

所謂位段是把一個(gè)字單元中的二進(jìn)制位劃分為幾個(gè)不同的區(qū)段,并說明每個(gè)區(qū)段的位數(shù)。每個(gè)區(qū)段有一個(gè)位段名,允許在程序中按位段名進(jìn)行操作。這樣就可以把幾個(gè)不同的對象用一個(gè)字單元的幾個(gè)二進(jìn)制位段來表示。位段定義就是把一個(gè)存儲器字單元定義成一個(gè)位段結(jié)構(gòu)體,一個(gè)位段是結(jié)構(gòu)體中的一個(gè)成員。位段定義的一般形式為

其中,類型是指位段中數(shù)據(jù)的類型,位段名是位段引用的標(biāo)識符,位數(shù)是位段所占的存儲位,即二進(jìn)制位數(shù)。位段位數(shù)之和小于或等于系統(tǒng)字長。位段名可以沒有,表示空位段。位段的使用就是結(jié)構(gòu)體成員的引用方法。例如:定義了3個(gè)有名位段a、b和c,分別占4位、3位和1位,存儲無符號類型數(shù)。包含一個(gè)無名位段,占4位,因?yàn)闊o名位段不能引用,所以相當(dāng)于空位段,只占據(jù)位數(shù)。字長是32位的系統(tǒng),定義位段后,字單元還剩余32-4-4-3-1=20(位),用“inti;”說明,表示可以存放整型數(shù)。若要給字段賦值,可用以下賦值語句:

bitdata.a=10;

bitdata.b=8;

bitdata.c=1;

每一位段定義之后,位數(shù)確定了位段的取值范圍,賦值不能超出取值范圍。若定義無符號字段的位數(shù)為k,則取值范圍為0~2k-1。

關(guān)于位段定義和使用的幾點(diǎn)說明:

(1)無名字段只用來作填充或調(diào)整位置,是不能使用的。

(2)一個(gè)位段必須存儲在一個(gè)單元中,不能跨兩個(gè)單元。如果第一個(gè)單元不能容納下一個(gè)位段,則從下一個(gè)單元起存放該位段。若某一位段要從另一個(gè)單元開始存放,可以采用如下形式定義:

溫馨提示

  • 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)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論