第12章編譯預處理_第1頁
第12章編譯預處理_第2頁
第12章編譯預處理_第3頁
第12章編譯預處理_第4頁
第12章編譯預處理_第5頁
已閱讀5頁,還剩18頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第第12章章 編譯預處理編譯預處理每個每個C編譯系統(tǒng)都提供了一組預處理命令。編譯預處理命令都是編譯系統(tǒng)都提供了一組預處理命令。編譯預處理命令都是以以“#”開頭,它不是開頭,它不是C語句,必須單獨占一行,末尾不使用分號作為語句,必須單獨占一行,末尾不使用分號作為結束符。結束符。在在C的源程序被編譯以前,首先對源程序中的預處理命令進行處的源程序被編譯以前,首先對源程序中的預處理命令進行處理,然后才對程序進行編譯。預處理命令可以出現(xiàn)在源程序的任何理,然后才對程序進行編譯。預處理命令可以出現(xiàn)在源程序的任何地方,但一般放在源程序的開頭,作用域是從當前所放置的地方開地方,但一般放在源程序的開頭,作用域是從

2、當前所放置的地方開始到文件結束,超出文件就失去作用。始到文件結束,超出文件就失去作用。 12.1 宏定義宏定義在在C源程序中,允許用一個標識符來表示一個字符串,稱為源程序中,允許用一個標識符來表示一個字符串,稱為“宏宏”,宏是一種編譯預處理命令。被定義為宏是一種編譯預處理命令。被定義為“宏宏”的標識符稱為的標識符稱為“宏名宏名”。在編譯預處理時,對程序中所有出現(xiàn)的在編譯預處理時,對程序中所有出現(xiàn)的“宏名宏名”都用宏定義中的字都用宏定義中的字符串去替換,這稱為符串去替換,這稱為“宏替換宏替換”或或“宏展開宏展開”。宏定義是由源程序中的。宏定義是由源程序中的宏定義命令完成的。宏替換是由預處理程序自

3、動完成的。宏定義命令完成的。宏替換是由預處理程序自動完成的。12.1.1無參宏定義無參宏定義1. 無參宏定義命令的語法格式無參宏定義命令的語法格式無參宏定義命令的一般格式如下:無參宏定義命令的一般格式如下:#define 標識符標識符 字符串字符串其中,其中,“標識符標識符”為所定義的宏名。為所定義的宏名。“字符串字符串”可以是常數(shù)、表達式、可以是常數(shù)、表達式、格式串等。格式串等。#define命令出現(xiàn)在程序中所有函數(shù)的外面,宏名的有效范圍為命令出現(xiàn)在程序中所有函數(shù)的外面,宏名的有效范圍為定義命令之后到本源文件結束,但可用定義命令之后到本源文件結束,但可用#undef命令終止宏定義的作用域。命

4、令終止宏定義的作用域。在前面介紹過的符號常量的定義就是一種無參宏定義。在前面介紹過的符號常量的定義就是一種無參宏定義。例如,以下命令定義宏名例如,以下命令定義宏名PI代表圓周率代表圓周率3.14159:#define PI 3.141592. 說明說明(1)根據一般)根據一般C程序中變量的命名規(guī)則,符號常量的定義一般習慣使用程序中變量的命名規(guī)則,符號常量的定義一般習慣使用大寫字母表示,這主要是因為通常在一般變量的定義中,常使用小寫字母大寫字母表示,這主要是因為通常在一般變量的定義中,常使用小寫字母的原因。當然,符號常量也可以小寫字母命名。的原因。當然,符號常量也可以小寫字母命名。(2)宏定義是

5、用宏名來表示一個字符串,在宏展開時又以該字符串?。┖甓x是用宏名來表示一個字符串,在宏展開時又以該字符串取代宏名,屬于一種簡單的代換。其中,所表示的字符串可含任意字符,可代宏名,屬于一種簡單的代換。其中,所表示的字符串可含任意字符,可以是常數(shù),也可以是表達式,預處理程序對它不作任何檢查。如有錯誤,以是常數(shù),也可以是表達式,預處理程序對它不作任何檢查。如有錯誤,只能在編譯已被宏展開的源程序的過程中發(fā)現(xiàn)問題。只能在編譯已被宏展開的源程序的過程中發(fā)現(xiàn)問題。(3)宏定義常用于程序中反復使用的表達式。)宏定義常用于程序中反復使用的表達式。(4)當宏定義在一行中寫不下,需要在下一行繼續(xù)時,只需在最后一)當

6、宏定義在一行中寫不下,需要在下一行繼續(xù)時,只需在最后一個字符后緊接著加一個反斜線個字符后緊接著加一個反斜線“”。例如:。例如:#define LEAP_YEAR year%4=0 & year%100!=0 | year%400=0(5)宏定義不是語句,在行末不必加分號,如加上分號則連分號也一)宏定義不是語句,在行末不必加分號,如加上分號則連分號也一起置換。例如,以下程序沒有語法錯誤,能正確運行,執(zhí)行結果為起置換。例如,以下程序沒有語法錯誤,能正確運行,執(zhí)行結果為4:#include #define X 2;void main() int y; y=2*X /*其后沒有逗號,但宏展開為

7、:其后沒有逗號,但宏展開為:y=2*2;是正確的語句是正確的語句*/ printf(%dn,y); (6)宏名在源程序中若用引號括起來,則預處理程序不對其作宏替換。)宏名在源程序中若用引號括起來,則預處理程序不對其作宏替換。例如:例如:#include #define STR this is a stringvoid main()printf(STR=%sn,STR);在括號內的在括號內的STR不展開,只展開第二個不展開,只展開第二個str。輸出為:。輸出為:STR=this is a string(7)宏定義允許嵌套,即在宏定義的字符串中可以使用已經定義的宏)宏定義允許嵌套,即在宏定義的字符

8、串中可以使用已經定義的宏名,并且在宏展開時由預處理程序層層代換。例如:名,并且在宏展開時由預處理程序層層代換。例如:#define X 2+3#define Y X*X在程序設計中,如有語句:在程序設計中,如有語句:printf(%dn,Y);則在宏替換后變?yōu)椋簞t在宏替換后變?yōu)椋簆rintf(%sn,2+3*2+3);結果輸出結果輸出11。(8)宏定義是預處理指令,與定義變量不同,它只是進行簡單的字符)宏定義是預處理指令,與定義變量不同,它只是進行簡單的字符串替換,不分配內存。串替換,不分配內存。12.1.2 帶參宏定義帶參宏定義C允許宏帶有參數(shù)。在宏定義中的參數(shù)稱為形式參數(shù),簡稱為形參,在允

9、許宏帶有參數(shù)。在宏定義中的參數(shù)稱為形式參數(shù),簡稱為形參,在宏調用中的參數(shù)稱為實際參數(shù),簡稱為實參。對帶參數(shù)的宏,在調用中,宏調用中的參數(shù)稱為實際參數(shù),簡稱為實參。對帶參數(shù)的宏,在調用中,不僅要宏展開,而且要用實參去代換形參。不僅要宏展開,而且要用實參去代換形參。1. 帶參宏定義命令的語法格式帶參宏定義命令的語法格式帶參宏定義命令的一般格式如下:帶參宏定義命令的一般格式如下:#define 標識符標識符(形參表形參表) 字符串字符串其中,括號中的其中,括號中的“形參表形參表”是由一個或多個形參組成的,當有一個以上是由一個或多個形參組成的,當有一個以上的形參時,形參之間用逗號分隔。對帶參宏的展開也

10、是用字符串代替宏名,的形參時,形參之間用逗號分隔。對帶參宏的展開也是用字符串代替宏名,但是其中的形參要用相應的實參代替。但是其中的形參要用相應的實參代替。2. 帶參宏調用的語法格式帶參宏調用的語法格式帶參宏調用的一般格式如下:帶參宏調用的一般格式如下:宏名宏名(實參表實參表)例如:例如:#define M(x,y) x*x+y*yy=M(2,4);在宏調用時,用實參在宏調用時,用實參2代替形參代替形參x,4代替形參代替形參y,經預處理宏展開后,經預處理宏展開后的語句為:的語句為:y=2*2+4*4;3. 說明說明(1)帶參宏定義中,宏名和形參表之間不能有空格出現(xiàn)。例如:)帶參宏定義中,宏名和形

11、參表之間不能有空格出現(xiàn)。例如:#define MAX(a,b) (ab)?a:b/*正確形式正確形式*/寫為:寫為:#define MAX (a,b) (ab)?a:b /*錯誤形式錯誤形式:MAX與與(之間有空格之間有空格*/則程序中錯誤形式將被認為是無參宏定義,宏名則程序中錯誤形式將被認為是無參宏定義,宏名MAX代表代表(ab)?a:b,字符,字符串宏展開時,宏調用語句:串宏展開時,宏調用語句:max=MAX(x,y);將變?yōu)閷⒆優(yōu)閙ax=(a,b) (ab)?a:b(x,y);這顯然是錯誤的。這顯然是錯誤的。(2)在帶參宏定義中,形參不分配內存單元,因此不必作類型定義。而)在帶參宏定義中

12、,形參不分配內存單元,因此不必作類型定義。而宏調用中的實參有具體的值,要用它們去代換形參,因此必須作類型定義。宏調用中的實參有具體的值,要用它們去代換形參,因此必須作類型定義。這是與函數(shù)中的情況不同的。在函數(shù)中,形參和實參是兩個不同的量,各這是與函數(shù)中的情況不同的。在函數(shù)中,形參和實參是兩個不同的量,各有自己的作用域,調用時要把實參值賦予形參,進行有自己的作用域,調用時要把實參值賦予形參,進行“值傳遞值傳遞”。而在帶。而在帶參宏中,只是符號代換,不存在值傳遞的問題。參宏中,只是符號代換,不存在值傳遞的問題。(3)在宏定義中的形參是標識符,而宏調用中的實參可以是表達式。)在宏定義中的形參是標識符

13、,而宏調用中的實參可以是表達式。(4)在宏定義中,字符串內的形參通常要用括號括起來以避免出錯。)在宏定義中,字符串內的形參通常要用括號括起來以避免出錯?!纠纠?2.1】 定義求正方形面積的宏。定義求正方形面積的宏。解:解:對應的宏定義如下:對應的宏定義如下:#define area(a) (a)*(a)其中,為什么要加上括號呢其中,為什么要加上括號呢?這是因為這是因為“宏替換宏替換”只是簡單的替換操作,只是簡單的替換操作,當當area的實際參數(shù)是一個表達式時,不加括號會在編譯時出錯。如若為:的實際參數(shù)是一個表達式時,不加括號會在編譯時出錯。如若為:#define area1(a) (a*a)

14、當調用當調用area1(2+3)時,替換成:時,替換成:(2+3*2+3)那么,求出的面積是那么,求出的面積是10,而不是正確的,而不是正確的25。(5)宏定義可用來定義多個語句,在宏調用時,把這些語句又代換到)宏定義可用來定義多個語句,在宏調用時,把這些語句又代換到源程序內。例如:源程序內。例如:#define SET(a,b,c,d) a=1;b=2;c=3;d=4在程序中的如下語句:在程序中的如下語句:SET(x,y,z,w);宏展開為:宏展開為:x=1;y=2;z=3;w=4;(6)帶參宏和函數(shù)如下幾方面的區(qū)別:)帶參宏和函數(shù)如下幾方面的區(qū)別:l 函數(shù)調用時,先求出實參表達式的值,然后

15、代入函數(shù)定義中的形參;函數(shù)調用時,先求出實參表達式的值,然后代入函數(shù)定義中的形參;而使用帶參宏只是進行簡單的字符替換,不進行實參的計算。而使用帶參宏只是進行簡單的字符替換,不進行實參的計算。l 函數(shù)調用是在程序運行時處理的,分配臨時的內存單元;而宏擴展函數(shù)調用是在程序運行時處理的,分配臨時的內存單元;而宏擴展則是在編譯之前進行的,在展開時并不分配內存單元,也不進行值則是在編譯之前進行的,在展開時并不分配內存單元,也不進行值的傳遞處理,也沒有的傳遞處理,也沒有“返回值返回值”的概念。的概念。l 對函數(shù)中的實參和形參都要定義類型,且兩者的類型要求一致,如對函數(shù)中的實參和形參都要定義類型,且兩者的類

16、型要求一致,如不一致應進行類型轉換;而宏不存在類型問題,宏名無類型,它的不一致應進行類型轉換;而宏不存在類型問題,宏名無類型,它的參數(shù)也無類型,只是一個符號代表,展開時代入指定的字符即可。參數(shù)也無類型,只是一個符號代表,展開時代入指定的字符即可。l 調用函數(shù)只可得到一個返回值,而用宏可以設法得到幾個結果。例調用函數(shù)只可得到一個返回值,而用宏可以設法得到幾個結果。例如,對于下面的宏定義:如,對于下面的宏定義:#define PI 3.14159#define CIRCLE(R,L,S) L=2*PI*R;S=PI*R*R若程序中出現(xiàn)語句:若程序中出現(xiàn)語句:CIRCLE(5,A,B);則宏擴展的結

17、果為:則宏擴展的結果為:A=2*3.14159*5;B=3.14159*5*5;顯然得到了兩個結果,即圓周長顯然得到了兩個結果,即圓周長A和圓面積和圓面積B。【例【例12.2】 分析以下程序的執(zhí)行結果。分析以下程序的執(zhí)行結果。/*FileName:exam12_2.cpp*/#include #define SQR(x) x*xvoid main() int a=10,k=2,m=1; a/=SQR(k+m)/SQR(k+m); printf(%dn,a);解:解:程序執(zhí)行結果如下:程序執(zhí)行結果如下:1一般情況下,一般情況下,C源程序中所有的行都參加編譯過程。但有時出于對源程序中所有的行都參加

18、編譯過程。但有時出于對程序代碼優(yōu)化的考慮,希望對其中一部分內容只是在滿足一定條件程序代碼優(yōu)化的考慮,希望對其中一部分內容只是在滿足一定條件時才進行編譯,形成目標代碼。時才進行編譯,形成目標代碼。這種對程序一部分內容指定編譯的條件稱為條件編譯。這種對程序一部分內容指定編譯的條件稱為條件編譯。12.2 條件編譯條件編譯1. 形式一形式一#if 常數(shù)表達式常數(shù)表達式 程序段程序段1;#else 程序段程序段2;#endif或者或者#if 常數(shù)表達式常數(shù)表達式 程序段;程序段;#endif該語句的作用是:首先求該語句的作用是:首先求“常數(shù)表達式常數(shù)表達式”的值,如果為真(非的值,如果為真(非0),),

19、就編譯就編譯“程序段程序段1”,否則編譯,否則編譯“程序段程序段2”。如果沒有。如果沒有#else部分,則當部分,則當“常數(shù)表達式常數(shù)表達式”的值為的值為0時,直接跳過時,直接跳過#endif。2. 形式二形式二#ifdef 宏名宏名 程序段程序段1;#else 程序段程序段2;#endif或者或者#ifdef 宏名宏名 程序段;程序段;#endif該語句的作用是,如果該語句的作用是,如果#ifdef后面的后面的“宏名宏名”在此之前已用在此之前已用#define語語句定義,就編譯句定義,就編譯“程序段程序段1”;否則編譯;否則編譯“程序段程序段2”。如果沒有。如果沒有#else部分,部分,則當

20、宏名未定義時直接跳過則當宏名未定義時直接跳過#endif。3. 形式三形式三#ifndef 宏名宏名 程序段程序段1;#else 程序段程序段2;#endif或者或者#ifndef 宏名宏名 程序段;程序段;#endif其中,其中,#ifndef語句的功能與語句的功能與#ifdef相反,如果宏名未定義則編譯相反,如果宏名未定義則編譯“程序程序段段1”;否則編譯;否則編譯“程序段程序段2”。【例【例12.7】 分析以下程序的執(zhí)行結果。分析以下程序的執(zhí)行結果。/*FileName:exam12_7.cpp*/#include void main()#ifndef xint x=1; #elsex=

21、2; #endifprintf(x=%dn,x);解:解:程序執(zhí)行結果如下:程序執(zhí)行結果如下:x=112.3 文件包括文件包括所謂文件包括預處理,是指在一個文件中將另一個文件的全部內容包所謂文件包括預處理,是指在一個文件中將另一個文件的全部內容包含進來的處理過程,即將另外的文件包括到本文件中。含進來的處理過程,即將另外的文件包括到本文件中。1. 文件包括的語法格式文件包括的語法格式C提供了提供了#include編譯預處理命令實現(xiàn)文件包括操作,其一般格式為:編譯預處理命令實現(xiàn)文件包括操作,其一般格式為:#include 或者或者#include 包括文件名包括文件名文件包括預處理的功能是,在對源

22、程序進行編譯之前,用包括文件文件包括預處理的功能是,在對源程序進行編譯之前,用包括文件的內容取代該文件包括預處理語句。的內容取代該文件包括預處理語句。例如,例如,a.cpp文件中有文件包括命令文件中有文件包括命令#include “b.cpp”,其預處理過,其預處理過程如下圖所示。程如下圖所示。2. 說明說明(1)一個)一個include命令只能指定一個包括文件。如果要包括多個文件,命令只能指定一個包括文件。如果要包括多個文件,則要使用多個則要使用多個include命令。命令。(2)如果文件)如果文件file1.cpp要使用文件要使用文件file2.cpp中的內容,而文件中的內容,而文件file2.cpp要用到文件要用到文件file3.cpp中的內容,則可以在文件中的內容,則可以在文件file1.cpp中用兩個中用兩個include命命令分別包含令分別包含file2.cpp和和file3.cpp,而且文件,而且文件file3.cpp應出現(xiàn)在文件應出現(xiàn)在文件file2.cpp之前,即在之前,即在file1.cpp中定義:中定義

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論