C語言的預(yù)處理器_第1頁
C語言的預(yù)處理器_第2頁
C語言的預(yù)處理器_第3頁
C語言的預(yù)處理器_第4頁
C語言的預(yù)處理器_第5頁
已閱讀5頁,還剩27頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、C語言的預(yù)處理器理解C語言編譯全過程n編譯的概念:編譯程序讀取源程序(字符流),對之進行詞法和語法的分析,將高級語言指令轉(zhuǎn)換為功能等效的匯編代碼,再由匯編程序轉(zhuǎn)換為機器語言,并且按照操作系統(tǒng)對可執(zhí)行文件格式的要求鏈接生成可執(zhí)行程序。nC語言組建的完整過程:C源程序預(yù)編譯處理(.c) 編 譯 、 優(yōu) 化 程 序 ( . s 、 . a s m ) 匯 編 程 序(.obj、.o、.a、.ko) 鏈接程序(.exe、.elf、.axf等)概述C+編譯系統(tǒng)預(yù)處理編譯連接編譯是將程序代碼編譯成目標文件(.obj)連接是將目標文件與庫文件連接成為可執(zhí)行文件(.exe)那么預(yù)處理是做什么的?預(yù)處理是用來處

2、理在C+源程序中加入的一些“預(yù)處理命令” (preprocessor directives)的。預(yù)處理命令是C+統(tǒng)一規(guī)定的一些預(yù)先處理語句,用以改進程序設(shè)計環(huán)境,提高編程效率。預(yù)處理命令不是C+語言本身的組成部分,不能直接對它們進行編譯和連接。C+與其他高級語言的一個重要區(qū)別是可以使用預(yù)處理命令和具有預(yù)處理的功能。預(yù)處理命令nC+提供的預(yù)處理功能主要有以下3種:() 宏定義() 文件包含() 條件編譯n分別用宏定義命令、文件包含命令、條件編譯命令來實現(xiàn)。為了與一般C+語句相區(qū)別,這些命令以符號“”開頭,而且末尾不包含分號。1 宏定義和宏替換n宏定義以#define開頭。用以將一個指定的標識符(

3、即宏名)來代表一個字符串。n定義宏的作用一般是用一個短的名字代表一個長的字符串。n宏定義可分為兩類:n不帶參數(shù)的宏定義1.帶參數(shù)的宏定義1.1 不帶參數(shù)的宏定義n不帶參數(shù)的宏定義是用一個用戶指定的,稱為宏名的標識符,來代表一個字符串。這種定義的一般形式為: #define 宏名 字符串n這就是已經(jīng)介紹過的定義符號常量。如: #define PI 3.1415926 顯然在程序中用這種方式定義常量有許多好處。n宏定義的作用是,宏名后面的字符串,在程序中可用相應(yīng)的宏名來代替。即程序中所有的PI在預(yù)處理后都將會替換成3.1415926。#include#define M (y*y+3*y)void

4、main( ) int nSum, nNumber; printf(input a number: ); scanf(%d, &nNumber); nSum = 3*M+4*M+5*M; printf(s=%dn, nSum); 1.2 帶參數(shù)的宏定義n宏名還可以帶參數(shù)。這時的宏替換,既進行字符串的替換,又進行參數(shù)的替換。帶參數(shù)的宏名還可以接受表達式的值,并賦給普通變量,就好象函數(shù)調(diào)用似的。n帶參數(shù)的宏定義的一般形式為:n#define 宏名(參數(shù)) 字符串n在字符串中也要包含著宏名定義的使用參數(shù)。如:n#define S(a,b) a*b /定義宏S(矩形面積),a、b為宏的參數(shù)n使

5、用的形式如下:narea=S(3,2)n用、分別代替宏定義中的形式參數(shù)a和b,即用3*2代替S(3,2)。因此賦值語句展開為:narea=3*2;多行宏n當用define定義一個多行的宏時,必須在宏定義的內(nèi)容中,用作為一行的結(jié)束,否則編譯器無法知道多行宏定義到哪一行為止。n使用多行宏可以代替函數(shù)。(初級多態(tài))n多行宏會有很多問題,使用時要特別注意:n不能加注釋n不能作為右值使用n不能作為函數(shù)參數(shù)使用n#include#define SQR(x, y)y =x*x; printf(nThe square of %d is %ld.n, x, y);#define TASK_BEGIN(calle

6、r, y) caller(1,y); caller(2,y); caller(3,y)int main(int argc, char* argv) int x,y; TASK_BEGIN(SQR,y); printf(nEnter an integer value:); scanf(%d, &x); SQR(x, y); return 0;n函數(shù)與帶參數(shù)宏的區(qū)別:n函數(shù)調(diào)用時,要計算實參并向形參傳送。n函數(shù)中的實參和形參有確定的數(shù)據(jù)類型,并且兩者是一一對應(yīng)的。n宏是在編譯前進行的,不分配內(nèi)存空間。 宏替換是不占程序的運行時間的,只占編譯時間。由于C+增加了內(nèi)置函數(shù)(inline),比用

7、帶參數(shù)的宏定義更方便,因此在C+中基本上已不再用#define命令定義宏函數(shù)了。這種簡單的替換帶來了重大隱這種簡單的替換帶來了重大隱患,使用時一定要十分小心患,使用時一定要十分小心C預(yù)定義宏nC標準指定了一些預(yù)定義宏,編程中常常用到。n_DATE_ 進行預(yù)處理的日期n_TIME_ 源文件的編譯時間n_FILE_ 代表當前源代碼文件名的字符串n_LINE_ 代表當前源代碼文件中行號的整數(shù)常量n_STDC_ 設(shè)置為1時,表示該實現(xiàn)遵循C標準n_STDC_HOSTED_ 為本機環(huán)境設(shè)置為1,否則設(shè)為0n_STDC_VERSION_ 為C99時設(shè)置為199901Ln_func_ C99提供的,為所在函

8、數(shù)名的字符串n對于_FILE_,_LINE_,_func_這樣的宏,在調(diào)試程序時是很有用的,因為你可以很容易的知道程序運行到了哪個文件的那一行,是哪個函數(shù).宏定義使用時,要注意以下幾個問題: n宏名一般用大寫字母,以便與變量名的區(qū)別。n在編譯預(yù)處理時宏名與字符串進行替換時,不作語法檢不作語法檢查查。n宏名的有效范圍是從定義位置到文件結(jié)束。如果需要終止宏定義的作用域,可以用#undef#undef命令。例如 #define PI 3.14159 void main() # undef PI f1()n宏定義時可以引用已經(jīng)定義的宏名。n對程序中用雙引號擴起來的字符串內(nèi)的字符,不進行宏不進行宏的替換

9、的替換操作。 PI的作用域表示PI只在main函數(shù)中有效,在f1中無效。宏的妙用考慮求兩參數(shù)之中大值函數(shù):考慮求兩參數(shù)之中大值函數(shù):max ( a , b )對對 a , b 的不同類型,都有相同的處理形式:的不同類型,都有相同的處理形式:return ( a b ) ? a : b ;數(shù)據(jù)類型抽象:數(shù)據(jù)類型抽象:(1)宏替換)宏替換 # define max ( a , b ) ( a b ? a : b) 問題問題 避開類型檢查避開類型檢查(2)重載)重載問題問題 需要許多重載版本需要許多重載版本(3)使用函數(shù)模板)使用函數(shù)模板宏的妙用n初級多態(tài)n宏名抽象n函數(shù)抽象#include#def

10、ine SQR(x, y)y =x*x; printf(nThe square of %d is %ld.n, x, y);#define TASK_BEGIN(caller, y) caller(1,y); caller(2,y); caller(3,y)int main(int argc, char* argv) int x,y; TASK_BEGIN(SQR,y); printf(nEnter an integer value:); scanf(%d, &x); SQR(x, y); return 0;void SQR(int x, int y) y =x*x; printf(n

11、The square of %d is %ld.n, x,y);宏的誤用#include#define M y*y+3*yvoid main( ) int nSum, nNumber; printf(input a number: ); scanf(%d, &nNumber); nSum = 3*M+4*M+5*M; printf(s=%dn, nSum); #define SQR(x) printf(in #define!); x*xint main(int argc, char* argv) int x,y; printf(nEnter an integer value:); sc

12、anf(%d, &x); y = SQR(x); printf(nThe square of %d is %ldn, x, y); return 0;#define SQUARE(a) (a)*(a)void main( )/計算窗口面積int a=150;/客戶區(qū)邊長int b;b=SQUARE(+a + 3); 2 文件包含1.“1.“文件包含文件包含”的作用的作用n所謂“文件包含”處理是指一個源文件可以將另外一個源文件的全部內(nèi)容包含進來,即將另外的文件包含到本文件之中。nC提供了#include命令用來實現(xiàn)“文件包含”的操作。n文件包含預(yù)處理命令的一般形式: #include n

13、或者 #include “文件名”n處理過程:預(yù)編譯時,用被包含文件的內(nèi)容取代該預(yù)處理命令,再對“包含”后的文件作一個源文件編譯。n如在file1.c中有以下#include命令: n#include 它的作用如下圖所示:/例9.8讀取用戶輸入的數(shù)字,并顯示其平方。/源文件calc1.h的內(nèi)容如下:long sqr( int x )return ( long )x*x);/源文件calc.c的內(nèi)容如下:#include #include calc1.hvoid main()int x;printf(Enter an integer value:);scanf(%d, &x);print

14、f(nThe square of %d is %ld.n, x, sqr(x);“文件包含”處理n“文件包含”命令是很有用的,它可以節(jié)省程序設(shè)計人員的重復(fù)勞動。n#include命令的應(yīng)用很廣泛,絕大多數(shù)C程序中都包括#include命令?,F(xiàn)在,庫函數(shù)的開發(fā)者把這些信息寫在一個文件中,用戶只需將該文件“包含”進來即可(如調(diào)用數(shù)學(xué)函數(shù)的,應(yīng)包含math.h文件),這就大大簡化了程序,寫一行#include命令的作用相當于寫幾十行、幾百行甚至更多行的內(nèi)容。這種常用在文件頭部的被包含的文件稱為“標題文件”或“頭部文件”?!拔募碧幚韓頭文件一般包含以下幾類內(nèi)容: n對類型的聲明。n函數(shù)聲明。n內(nèi)

15、置(inline)函數(shù)的定義。n宏定義。用#define定義的符號常量和用const聲明的常變量。n全局變量定義。n外部變量聲明。如entern int a; n還可以根據(jù)需要包含其他頭文件。(1)不同的頭文件包括以上不同的信息,提供給程序設(shè)計者使用,這樣,程序設(shè)計者不需自己重復(fù)書寫這些信息,只需用一行#include命令就把這些信息包含到本文件了,大大地提高了編程效率。由于有了#include命令,就把不同的文件組合在一起,形成一個文件。因此說,頭文件是源文件之間的接口?!拔募碧幚?. include2. include命令的兩種形式命令的兩種形式n在#include命令中,文件名除了

16、可以用尖括號括起來以外,還可以用雙撇號括起來。#include命令的一般形式為:n#include n或n#include “文件名”n如:n#include n或n#include “iostream”n都是合法的?!拔募碧幚韓有時被包含的文件不一定在系統(tǒng)目錄中,這時應(yīng)該用雙撇號形式,在雙撇號中指出文件路徑和文件名。n如果在雙撇號中沒有給出絕對路徑,如#include file2.c則默認指用戶當前目錄中的文件。系統(tǒng)先在用戶當前目錄中尋找要包含的文件,若找不到,再按標準方式查找。如果程序中要包含的是用戶自己編寫的文件,宜用雙撇號形式。n對于系統(tǒng)提供的頭文件,既可以用尖括號形式,也可以用

17、雙撇號形式,都能找到被包含的文件,但顯然用尖括號形式更直截了當,效率更高?!拔募碧幚韓二者的區(qū)別是: 用尖括號時,編譯系統(tǒng)到系統(tǒng)目錄中尋找要包含的文件,如果找不到,編譯系統(tǒng)就給出出錯信息。n有時被包含的文件不一定在系統(tǒng)目錄中,這時應(yīng)該用雙撇號形式,在雙撇號中指出文件路徑和文件名。n如果在雙撇號中沒有給出絕對路徑,如#include file2.c則默認指用戶當前目錄中的文件。系統(tǒng)先在用戶當前目錄中尋找要包含的文件,若找不到,再按標準方式查找。如果程序中要包含的是用戶自己編寫的文件,宜用雙撇號形式。n對于系統(tǒng)提供的頭文件,既可以用尖括號形式,也可以用雙撇號形式,都能找到被包含的文件,但顯然

18、用尖括號形式更直截了當,編譯效率更高?!拔募碧幚?. 3. 關(guān)于關(guān)于C C語言標準庫語言標準庫 n在C編譯系統(tǒng)中,提供了許多系統(tǒng)函數(shù)和宏定義,而對函數(shù)的聲明則分別存放在不同的頭文件中。如果要調(diào)用某一個函數(shù),就必須用#include命令將有關(guān)的頭文件包含進來。C的庫除了保留C的大部分系統(tǒng)函數(shù)和宏定義外,還增加了預(yù)定義的模板和類。但是不同C庫的內(nèi)容不完全相同,由各C編譯系統(tǒng)自行決定。不久前推出的C標準將庫的建設(shè)也納入標準,規(guī)范化了C標準庫,以便使C程序能夠在不同的C平臺上工作,便于互相移植。新的C標準庫中的頭文件一般不再包括后綴.h,例如:n#include “文件包含”處理n但為了使大批已

19、有的C程序能繼續(xù)使用,許多C+編譯系統(tǒng)保留了C的頭文件,即提供兩種不同的頭文件,由程序設(shè)計者選用。如n#include /C形式的頭文件n#include /C+形式的頭文件n效果基本上是一樣的。建議盡量用符合C+標準的形式,即在包含C+頭文件時一般不用后綴。如果用戶自己編寫頭文件,可以用.h為后綴。3 條件編譯n一般情況下,在進行編譯時對源程序中的每一行都要編譯。但是有時希望程序中某一部分內(nèi)容只在滿足一定條件時才進行編譯,也就是指定對程序中的一部分內(nèi)容進行編譯的條件。如果不滿足這個條件,就不編譯這部分內(nèi)容。這就是“條件編譯”。n有時,希望當滿足某條件時對一組語句進行編譯,而當條件不滿足時則編

20、譯另一組語句。n條件編譯命令常用的有以下形式:3.1 #if_#endif類型的條件編譯命令1. #if_#endif1. #if_#endif:n此命令的一般形式為:#if 常數(shù)表達式 程序段#endifn如果常數(shù)表達式為真,則編譯if后面的程序段(語句塊);否則就不編譯,跳過這段程序。2. #if_#else_#endif2. #if_#else_#endifn此命令的一般形式為:#if 常量表達式 程序段1#else 程序段2#endif3. #if_#elif_#endif3. #if_#elif_#endifn這是用于多路選擇的編譯命令。它的一般形式為:#if 常量表達式1 程序段1

21、#elif 常量表達式2 程序段2 .#elif 常量表達式n 程序段n#endif3.2 #ifdef和#ifndef類型的條件編譯命令1. #ifdef_#endif1. #ifdef_#endif類型條件編譯命令類型條件編譯命令n第一種格式為:n#ifdef 宏名n 程序段n#endifn 第二種格式為:n#ifdef 宏名n 程序段1n#elsen 程序段2n#endif2. #ifndef_#endif2. #ifndef_#endif類型條件編譯命令類型條件編譯命令n第一種格式為:n#ifndef 宏名n 程序段1n#endifn第二種格式為:n#ifndef 宏名n 程序段1n#elsen 程序段2n#endif條件編譯舉例#include using namespace std;#define RUN /在調(diào)試程序時使之成為注釋行int main( ) int x=1,y=2,z=3;#ifndef RUN /本行

溫馨提示

  • 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)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論