cc程序設(shè)計(jì)第7章-編譯預(yù)處理和位運(yùn)算課件_第1頁
cc程序設(shè)計(jì)第7章-編譯預(yù)處理和位運(yùn)算課件_第2頁
cc程序設(shè)計(jì)第7章-編譯預(yù)處理和位運(yùn)算課件_第3頁
cc程序設(shè)計(jì)第7章-編譯預(yù)處理和位運(yùn)算課件_第4頁
cc程序設(shè)計(jì)第7章-編譯預(yù)處理和位運(yùn)算課件_第5頁
已閱讀5頁,還剩24頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、C/C+程序設(shè)計(jì) C/C+程序設(shè)計(jì)第7章 編譯預(yù)處理和位運(yùn)算第7章 編譯預(yù)處理和位運(yùn)算 引言 編譯預(yù)處理是C語言編譯系統(tǒng)的一個(gè)組成部分。所謂編譯預(yù)處理是指在對(duì)源程序進(jìn)行編譯之前,先對(duì)源程序中的編譯預(yù)處理命令進(jìn)行處理,然后再將處理的結(jié)果和源程序一起進(jìn)行編譯,以得到目標(biāo)代碼,預(yù)處理的實(shí)現(xiàn)方法是通過幾種特殊的命令,在進(jìn)行程序的編譯之前,先對(duì)這些命令進(jìn)行處理。這些預(yù)處理命令的介入,可以改進(jìn)程序的設(shè)計(jì)環(huán)境,提高編程效率。 編譯預(yù)處理命令均以符號(hào)“#”開頭,并且規(guī)定一行只能寫一條預(yù)處理命令,命令結(jié)束不能使用分號(hào),通常預(yù)處理命令都放在源程序的開頭。在前面幾章的程序中,我們用到的#define 、#inclu

2、de等命令都是編譯預(yù)處理的應(yīng)用。 C語言提供了3種預(yù)處理命令:宏定義文件包含條件編譯第7章 編譯預(yù)處理和位運(yùn)算 C語言有兩種宏定義命令,一種是不帶參數(shù)的宏定義(也稱符號(hào)常量定義),另一種是帶參數(shù)的宏定義。7.1 編譯預(yù)處理- 宏定義1. 不帶參數(shù)的宏定義一般格式為:#define 標(biāo)識(shí)符 字符串說明:1)通常宏名用大寫字母表示,以示與普通變量區(qū)別。2)宏名與字符替換序列之間用空格符分隔。3)編譯預(yù)處理時(shí),在程序中進(jìn)行宏替換(也稱宏展開),凡是 宏名出現(xiàn)的地方均被替換為它所對(duì)應(yīng)的字符替換序列。4)編譯預(yù)處理時(shí)只做簡單的替換,不進(jìn)行語法檢查更不會(huì)做運(yùn) 算,若字符串有錯(cuò)誤,只有在正式編譯時(shí)才會(huì)進(jìn)行檢

3、查。5)沒有特殊的需要,一般在預(yù)處理語句的行末不必加分號(hào),若 加了分號(hào),則連同分號(hào)一起替換。6)使用宏定義可以減少程序中重復(fù)書寫字符串的工作量,提高 程序的可移植性。#define PI 3.14159f ; area = PI * r * r ;經(jīng)過宏替換后: area = 3.14159f ; * r * r ; ,顯然正式編譯時(shí)會(huì)報(bào)告語法錯(cuò)誤。 通常當(dāng)問題規(guī)模事先不能確定時(shí),可使用宏定義來定義一個(gè)表示問題規(guī)模的符號(hào)常量。如:#define N 1007)宏定義命令通常放在文件開頭或者函數(shù)定義之前,宏名的作用域通常從定義開始到所在源文件結(jié)束。但使用#undef命令可提前強(qiáng)制終止某個(gè)宏的作用

4、域。#define PI 3.14159fvoid main ( ) #undef PI / 結(jié)束宏名PI的作用域fun ( )PI的有效范圍 這里,#undef PI 之后的代碼范圍,符號(hào)常量PI的宏定義就不再起作用了。8)進(jìn)行宏定義時(shí),在字符替換序列中可以引用已定義的其它宏名,宏展開時(shí)會(huì)進(jìn)行層層替換。例如: #include #define PI 3.1415926f#define R 4.0f#define L 2*PI*R#define S PI*R*Rvoid main ( ) printf ( L=%f , S=%f n , L , S ) ; 經(jīng)過宏展開后,printf ( )函

5、數(shù)調(diào)用語句被宏替換為: printf (L=%f n,S=%f n, 2*3.14159f*4.0f , 3.14159f *4.0 f * 4.0f ) ; 2. 帶參數(shù)的宏定義帶參數(shù)的宏定義不僅要進(jìn)行簡單的字符串替換,而且還要進(jìn)行參數(shù)替換。一般形式為: #define ( ) 說明:1)宏定義時(shí),宏名與左括號(hào)之間不要出現(xiàn)空格,否則會(huì)將空格連同后面的所有替換字符序列都作為替換內(nèi)容進(jìn)行替換。例如:#define S ( a , b ) a* b 如果程序中有 y = S ( x , y ) ,則被展開為: y = ( a , b ) a* b( x , y )顯然這不是想要的結(jié)果。2)宏定義中

6、的參數(shù)稱為形參。程序中使用帶參數(shù)的宏時(shí),程序中的參數(shù)為實(shí)參,實(shí)參可以是常量、變量或表達(dá)式。宏展開時(shí),將替換序列中的形參用相應(yīng)位置的實(shí)參替換;若宏定義的替換序列中的字符不是形參,則在替換時(shí)保留。例如: #define S( a , b )a * barea = S( 2 , 3 ) ; 其中a和b稱為形參,2和3稱為實(shí)參,在宏展開時(shí),把2、3分別代替宏定義中的a、b,a * b中的“*”號(hào)保留,因此宏展開后語句為“area = 2 * 3 ;”。3)宏定義字符序列中的參數(shù)要用圓括號(hào)括起來,而且最好把整個(gè)字符串也用圓括號(hào)括起來,以保證在任何替換情況下都把宏定義作為一個(gè)整體,并且可以有一個(gè)合理的計(jì)算

7、順序,否則宏展開后,可能會(huì)出現(xiàn)意想不到的錯(cuò)誤。例如:#define S( r ) 3.14159 * r * rarea = S( a + b ) ; 經(jīng)過宏展開后變?yōu)椤癮rea = 3.14159 * a + b * a + b ;”顯然,由于宏定義時(shí),對(duì)r沒有加圓括號(hào)造成與設(shè)計(jì)的原意不符。那么,為了得到形如:area = 3.14159 * ( a + b ) * ( a + b ) ;就應(yīng)該在宏定義時(shí)給字符序列中的形參加上圓括號(hào),即: #define S ( r ) 3.14159 * ( r ) * ( r ) 【例7-1】從鍵盤輸入兩個(gè)數(shù),輸出較小的數(shù)。#include #defin

8、e MIN( a , b ) ( ( a ) ( b ) ? ( a ) : ( b ) ) void main( ) int x , y ;printf ( Please input two integers: ) ;scanf ( %d %d , &x , &y ) ;printf ( MIN = %d n, MIN ( x , y ) ) ; 類型區(qū)別函數(shù)帶參數(shù)的宏是否計(jì)算實(shí)參的值先計(jì)算出實(shí)參表達(dá)式的值,然后傳遞給形參變量。不計(jì)算實(shí)參表達(dá)式的值,直接用實(shí)參原樣進(jìn)行簡單的替換。何時(shí)進(jìn)行處理、分配內(nèi)存單元在程序運(yùn)行時(shí)進(jìn)行值的處理、調(diào)用函數(shù)時(shí)分配臨時(shí)的內(nèi)存單元。預(yù)編譯時(shí)進(jìn)行宏展開,不分配內(nèi)存單

9、元,不進(jìn)行值的處理。類型要求實(shí)參和形參要有類型聲明,且二者類型要匹配。不存在類型問題,只是一個(gè)符號(hào)表示。調(diào)用情況函數(shù)的代碼僅存在一個(gè)拷貝,對(duì)函數(shù)較大、調(diào)用次數(shù)較多時(shí)比較合算,但調(diào)用函數(shù)時(shí)會(huì)產(chǎn)生時(shí)間和空間的開銷。在程序源代碼中只要遇到宏符號(hào),都將其進(jìn)行宏替換,調(diào)用宏時(shí)沒有時(shí)間空間的開銷。但調(diào)用次數(shù)過多時(shí)會(huì)使程序代碼加長很多。參數(shù)傳遞方式有按值傳遞和按址傳遞方式對(duì)宏不存方式問題,就是簡單替換。3. 帶參數(shù)的宏與函數(shù)的區(qū)別7.1.2 文件包含文件包含是指一個(gè)源文件可以將另外一個(gè)源文件的全部內(nèi)容包含進(jìn)來,即將另一個(gè)C語言的源程序文件嵌入正在進(jìn)行預(yù)處理的源程序中相應(yīng)位置,一般形式為:#include 或

10、者#include 文件名 說明:1) “文件名”必須用一對(duì)尖括號(hào)或一對(duì)雙引號(hào)括起來。2) 使用尖括號(hào)和使用雙引號(hào)對(duì)應(yīng)著不同的路徑查找策略。尖括號(hào):系統(tǒng)直接在規(guī)定的磁盤目錄(通常為軟件安裝目 錄下的Include子目錄)查找文件。雙引號(hào) :首先在當(dāng)前文件所在目錄中查找文件,若沒有找 到,再在操作系統(tǒng)的path命令設(shè)置的各目錄中查找, 若還沒有找到,最后才在Include子目錄中查找。3) 一個(gè)#include命令只能指定一個(gè)被包含文件。7.1.2 文件包含4)若#include命令指定的文件內(nèi)容發(fā)生變化,則應(yīng)該對(duì)包含此文件的所有源文件重新編譯處理。5)文件包含命令可以嵌套使用,即一個(gè)被包含的文

11、件中可以再使用#include命令包含另一個(gè)文件,而在該文件中還可以再包含其它文件,通常允許嵌套10層以上?!纠?-2】分析圖7-1所示的幾個(gè)C源文件之間的包含關(guān)系。#include file2.cfile1.c中其余代碼#include file3.cfile2.c其余代碼file3.代碼cfile1.cfile2.cfile3.c分析: 通過#include “file3.c”命令,使file3.c的代碼被加入到文件file2.c中,而 #include “file2.c”又使file2.c被加入到 file1.c中,因此,通過預(yù)處理后,在文件“file1.c”中既有“file2.c”的代

12、碼也有“file3.c”的代碼。兩種形式: 指定表達(dá)式真假值 或者: 指定某種符號(hào)是否定義7.1.3 條件編譯 通常C源文件代碼都會(huì)參與編譯。但是,有時(shí)希望依據(jù)一定條件只對(duì)其中一部分代碼進(jìn)行編譯,這就是條件編譯。1. 指定某種符號(hào)已有定義的條件編譯命令格式:#ifdef 標(biāo)識(shí)符 程序段1 #else 程序段2 #endif說明:若標(biāo)識(shí)符已經(jīng)被定義過(一般用#define命令定義),那么編譯程序段1,否則編譯程序段2,其中#else部分為可選項(xiàng)。7.1.3 條件編譯【例7-3】分析下列條件編譯代碼。 #ifdef DEBUG printf ( x = %d ,y = %dn , x , y )

13、; #endif分析:若標(biāo)識(shí)符DEBUG被定義過,即程序中有宏定義“#define DEBUG”,則編譯程序就會(huì)編譯語句“printf(x=%d,y=%dn, x, y); ”,從而在程序運(yùn)行時(shí)輸出x,y的值。若沒有宏定義“#define DEBUG”,則此處的printf語句就不參加編譯,當(dāng)然也不會(huì)被執(zhí)行。 注意條件編譯與if語句有區(qū)別,即不參加編譯的程序段在目標(biāo)程序中沒有與之對(duì)應(yīng)的代碼。如果是if語句,則不管表達(dá)式是否為真,if語句中的所有語句都產(chǎn)生相應(yīng)的目標(biāo)代碼。7.1.3 條件編譯7.1.3 條件編譯2. 指定某種符號(hào)沒有定義的條件編譯命令格式: #ifndef 標(biāo)識(shí)符 程序段1 #e

14、lse 程序段2 #endif說明:其意義與#ifdef的意義恰好相反。若標(biāo)識(shí)符沒有定義,程序段1參加編譯,否則程序段2參加編譯。#else部分為可選項(xiàng)。如:#ifndef DEBUG printf ( x = %d , y = %dn , x , y ) ; #endif 若標(biāo)識(shí)符DEBUG沒有定義,則編譯printf語句,在程序運(yùn)行時(shí)輸出x,y的值;若有標(biāo)識(shí)符DEBUG的宏定義,則此處的printf語句就不參加編譯,也不被執(zhí)行。7.1.3 條件編譯3. 指定表達(dá)式真假值的條件編譯命令格式: #if 表達(dá)式 程序段1 #else 程序段 2#endif說明:若表達(dá)式為“真”(非0),編譯程序

15、段1,否則編譯程序段2。其中#else部分可以省略。例如:#include #define FLAG 1void main( ) int a = 1 , b = 0 ; #if FLAG a+ ; printf ( a = %d , a ) ; #else b- ; printf ( b = %d , b ) ; #endif此時(shí)FLAG為非0,則編譯語句“a+ ; printf (a = %d , a) ;”。注意:#if預(yù)處理語句中的表達(dá)式是在編譯階段計(jì)算值的,因而此處的表達(dá)式中不能出現(xiàn)變量,必須是常量或用#define定義的標(biāo)識(shí)符。7.1.3 條件編譯4.#undef 標(biāo)識(shí)符格式: #u

16、ndef 標(biāo)識(shí)符功能:將已定義的標(biāo)識(shí)符變?yōu)槲炊x的。例如:#include #define FLAG 1void main( ) int a = 1 , b = 0 ; #undef FLAG #ifdef FLAG a+ ; printf(a=%d ,a ) ; #else b- ; printf(b=%d ,b ) ; #endif雖然前面已經(jīng)定義標(biāo)識(shí)符FLAG,但程序中“#undef FLAG”命令后,標(biāo)識(shí)符FLAG已經(jīng)變?yōu)槲炊x,故下面程序段只編譯語句“b- ; printf ( b = %d , b ) ;”,程序運(yùn)行結(jié)果是b = -1。 程序中的所有數(shù)據(jù)在計(jì)算機(jī)內(nèi)存中都是以二進(jìn)制的

17、形式儲(chǔ)存的。在很多系統(tǒng)的程序開發(fā)中,都要求有對(duì)二進(jìn)制的位(bit)進(jìn)行一些運(yùn)算和處理。位運(yùn)算和位處理通常由低級(jí)語言來提供,而作為高級(jí)語言的C語言也提供了位運(yùn)算的功能。7.2 位運(yùn)算7.2 位運(yùn)算7.2.1 位運(yùn)算的概念和位運(yùn)算符 位運(yùn)算指對(duì)存儲(chǔ)單元中的數(shù)據(jù)按二進(jìn)制位進(jìn)行的運(yùn)算和處理。C語言提供了6種位運(yùn)算符:1)&(按位與) 2) | (按位或) 3) (按位異或) 4) (按位取反)5)(右移)說明:1)位運(yùn)算符中除了“”以外,均為二目運(yùn)算符。2)運(yùn)算對(duì)象只能是整型或字符型,不能為實(shí)型。3)運(yùn)算對(duì)象均以二進(jìn)制補(bǔ)碼的形式進(jìn)行運(yùn)算。4)位運(yùn)算符的優(yōu)先級(jí)順序?yàn)椋?(高于)(高于)&(高于)(高于)

18、| 。5)可以與賦值運(yùn)算符結(jié)合成為復(fù)合賦值運(yùn)算符。7.2 位運(yùn)算7.2.2 不同位運(yùn)算的運(yùn)算規(guī)則1. “按位與”運(yùn)算(&) 將兩個(gè)操作數(shù)的對(duì)應(yīng)二進(jìn)制位進(jìn)行邏輯與運(yùn)算。運(yùn)算規(guī)則:將對(duì)象的二進(jìn)制數(shù)補(bǔ)碼低位對(duì)齊,當(dāng)對(duì)應(yīng)位都為1該位的運(yùn)算結(jié)果為1,否則為0。例如:6&5。應(yīng)先把6和5以補(bǔ)碼表示,再進(jìn)行按位與運(yùn)算。運(yùn)算過程如下:6的補(bǔ)碼:0000 01105的補(bǔ)碼:0000 0101&運(yùn)算: 0000 0100再如:-6&5-6的補(bǔ)碼: 111110105的補(bǔ)碼: 00000101&運(yùn)算: 0000 0000(注意,運(yùn)算結(jié)果也是補(bǔ)碼,故6&5的結(jié)果是4)(注意,運(yùn)算結(jié)果也是補(bǔ)碼,故-6&5的結(jié)果是0)7

19、.2 位運(yùn)算說明:1)按位與運(yùn)算的結(jié)果也是補(bǔ)碼形式。2)“按位與”運(yùn)算通常用于對(duì)一個(gè)數(shù)中的某些位清0,即需要清0的位與“0”相與。這樣不需清0的位仍保持原值不變?!纠?-4】變量n為一正整數(shù),寫出判斷n是奇數(shù)的表達(dá)式。分析: 判斷一個(gè)整數(shù)是否為的常規(guī)表達(dá)式為:n % 2 != 0 或 n % 2,在此給出另一種判斷方法為:n & 1 != 0 或 n & 1 思考一下,為什么?7.2 位運(yùn)算2. “按位或”運(yùn)算() 將兩個(gè)操作數(shù)的對(duì)應(yīng)二進(jìn)制位進(jìn)行或運(yùn)算。運(yùn)算規(guī)則:如果兩個(gè)相應(yīng)位有一個(gè)為1,則該位的結(jié)果為1; 如果兩個(gè)相應(yīng)位都為0,則該位的結(jié)果為0。例如:0 x65 | 0 x35。運(yùn)算過程如下:0 x65的補(bǔ)碼:0110 01010 x35的補(bǔ)碼:0011 0101 | 運(yùn)算: 0111 0101說明:“按位或”運(yùn)算通常用于將一個(gè)數(shù)中的某些二進(jìn)制位設(shè)置成1,即需要置1的那些位與“1”相或。(注意:結(jié)果是補(bǔ)碼。故,0 x65 | 0 x35的結(jié)果是0 x75)【例7-5】設(shè)變量n為一正整數(shù),請(qǐng)將該數(shù)最低位字節(jié)中的偶數(shù)位全部置為1,試寫出能實(shí)現(xiàn)

溫馨提示

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