版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
C中的預(yù)處理命令是由ANSIC統(tǒng)一規(guī)定的,但它不是C語言的本身組成部分,不能直接對它們進(jìn)行編譯,因?yàn)榫幾g程序無法識別它們。必須對程序進(jìn)行通常的編譯(包括詞法和語法分析,代碼生成,優(yōu)化等)之前,先對程序中這些特殊的命令進(jìn)行“預(yù)處理”,例如:如果程序中用#include命令包含一個文件“stdio.h”,則在預(yù)處理時,將stdio.h文件中的實(shí)際內(nèi)容代替該命令。經(jīng)過預(yù)處理后的程序就像沒有使用預(yù)處理的程序一樣干凈了,然后再由編譯程序?qū)λM(jìn)行編譯處理,得到可供執(zhí)行的目標(biāo)代碼。現(xiàn)在的編譯系統(tǒng)都包括了預(yù)處理,編譯和連接部分,在進(jìn)行編譯時一氣呵成。我們要記住的是預(yù)處理命令不是C語言的一部分,它是在程序編譯前由預(yù)處理程序完成的。C提供的預(yù)處理功能主要有三種:宏定義,文件包含,條件編譯。它們的命令都以“#”開頭。一,宏定義:用一個指定的標(biāo)識符來代表一個字符串,它的一般形式為:#define標(biāo)識符字符串#definePI3.1415926我們把標(biāo)識符稱為“宏名”,在預(yù)編譯時將宏名替換成字符串的過程稱為“宏展開”,W#define是宏定義命令。幾個應(yīng)該注意的問題:1, 是用宏名代替一個字符串,也就是做簡單的置換,不做正確性檢查,如把上面例子中的1寫為小寫字母l,預(yù)編譯程序是不會報錯的,只有在正式編譯是才顯示出來。2, 宏定義不是C語句,不必在行未加分號,如果加了分號則會連分號一起置換。3,#define語句出現(xiàn)在程序中函數(shù)的外面,宏名的有效范圍為定義命令之后到本源文件結(jié)束,通常#define命令寫在文件開頭,函數(shù)之前,作為文件的一部分,在此文件范圍內(nèi)有效。4,可以用#undef命令終止宏定義的作用域。如:#definePI3.1415926main(){}#undefPImysub(){}則在mysub中PI不代表3.1415926。5, 在進(jìn)行宏定義時,可以引用已定義的宏名,可以層層置換。6, 對程序中用雙撇號括起來的字符串內(nèi)的字符,即使與宏名相同,也不進(jìn)行置換。7, 宏定義是專門用于預(yù)處理命令的一個專有名詞,它與定義變量的含義不同,只做字符替換不做內(nèi)存分配。帶參數(shù)的宏定義,不只進(jìn)行簡單的字符串替換,還進(jìn)行參數(shù)替換。定義的一般形式為:#define宏名(參數(shù)表)字符串如:#defineS(a,b)a*b,具體使用的時候是intarea;area=(2,3);對帶參數(shù)的宏定義是這樣展開置換的:在程序中如果有帶參數(shù)的宏(如area=(2,3)),則按#define命令行中指定的字符串從左到右進(jìn)行置換。如果串中包含宏中的形參(如a,b),貝0將程序語句中的相關(guān)參數(shù)(可以是常量,變量,或表達(dá)式)代替形參。如果宏定義中的字符串中的字符不是參數(shù)字符(如上*),則保留,這樣就形成了置換的字符串。帶參數(shù)的宏與函數(shù)有許多相似之處,在調(diào)用函數(shù)時也是在函數(shù)名后的括號內(nèi)寫實(shí)參,也要求實(shí)參與形參的數(shù)目相等,但它們之間還有很大的不同,主要有:1, 函數(shù)調(diào)用時,先求出實(shí)參表達(dá)式的值,然后代入形參,而使用帶參的宏只是進(jìn)行簡單的字符替換。函數(shù)調(diào)用是在程序運(yùn)行時處理的,為形參分配臨時的內(nèi)存單元。而宏展開則是在編譯前進(jìn)行的,在展開時并不分配內(nèi)存單元,不進(jìn)行值的傳遞處理,也沒有返回值的概念。3, 對函數(shù)中的實(shí)參和形參都要定義類型,二者的類型要求一致,如不一致,應(yīng)進(jìn)行類型轉(zhuǎn)換;而宏不存在類型問題,宏名無類型,它的參數(shù)也無類型,只是一個符號代表,展開時代入指定的字符串即可。宏定義時,字符串可以是任何類型的數(shù)據(jù)。4, 函數(shù)調(diào)用只可得到一個返回值,而用宏可以設(shè)法得到幾個結(jié)果。5, 使用宏次數(shù)多時,宏展開后源程序長,因?yàn)闆]展開一次都使程序增長,而函數(shù)調(diào)用不會這樣。6, 宏替換不占運(yùn)行時間,只占編譯時間,而函數(shù)調(diào)用則占運(yùn)行時間(分配單元,保留現(xiàn)場,值傳遞,返回)。二,文件包含:一個源文件可以將另一個源文件的全部內(nèi)容包含進(jìn)來,即將另外的文件包含到本文件中。#include<文件名〉或#include“文件名”感覺它像JAVA中的包,而它的作用像在J2EE中我們可以用*.xml做配置文件,然后各個模塊調(diào)用這個文件,但這個文件如果修改后,凡使用(包含)此文件的所有文件(因?yàn)槭褂脮r是拷貝了原來的一份)有都需要從新編譯,好像又失去了靈活的意義。在#include命令中,文件名可以用“”或<>括起來,它們的區(qū)別是用。時,系統(tǒng)到存放在用戶當(dāng)前目錄中尋找要包含的文件,若找不到,再按照標(biāo)準(zhǔn)方式查找(即按尖括號的方式查找)。一般說來,如果是為調(diào)用庫函數(shù)而用#include命令來包含相關(guān)的頭文件,則用<>,以節(jié)省查找時間。如果要包含的是用戶自己編寫的文件(這種文件一般都在當(dāng)前目錄中),一般用“”,若文件不在當(dāng)前目錄中,“”內(nèi)可給出文件路徑。三,條件編譯一般情況下,源程序中的所有行都參加編譯。但有時希望對其中一部分內(nèi)容只在滿足一定條件才進(jìn)行編譯,也就是對一部分內(nèi)容指定編譯的條件,這就是條件編譯。1,#indef標(biāo)識符程序段1#else程序段2#endif當(dāng)所指定的標(biāo)識符已經(jīng)被#include命令定義過,則在程序編譯階段只編譯程序1,否則編譯程序段2。2,#if表達(dá)式程序段1#else程序段2#endif優(yōu)點(diǎn):采用條件編譯,可以減少被編譯的語句,從而減少目標(biāo)程序的長度,減少運(yùn)行時間,當(dāng)條件編譯段比較多時,目標(biāo)程序長度可大大減少。預(yù)處理過程掃描源代碼,對其進(jìn)行初步的轉(zhuǎn)換,產(chǎn)生新的源代碼提供給編譯器。可見預(yù)處理過程先于編譯器對源代碼進(jìn)行處理。在C語言中,并沒有任何內(nèi)在的機(jī)制來完成如下一些功能:在編譯時包含其他源文件、定義宏、根據(jù)條件決定編譯時是否包含某些代碼。要完成這些工作,就需要使用預(yù)處理程序。盡管在目前絕大多數(shù)編譯器都包含了預(yù)處理程序,但通常認(rèn)為它們是獨(dú)立于編譯器的。預(yù)處理過程讀入源代碼,檢查包含預(yù)處理指令的語句和宏定義,并對源代碼進(jìn)行響應(yīng)的轉(zhuǎn)換。預(yù)處理過程還會刪除程序中的注釋和多余的空白字符。預(yù)處理指令是以#號開頭的代碼行。#號必須是該行除了任何空白字符外的第一個字符。#后是指令關(guān)鍵字,在關(guān)鍵字和#號之間允許存在任意個數(shù)的空白字符。整行語句構(gòu)成了一條預(yù)處理指令,該指令將在編譯器進(jìn)行編譯之前對源代碼做某些轉(zhuǎn)換。下面是部分預(yù)處理指令:指令 用途# 空指令,無任何效果#include 包含一個源代碼文件#define 定義宏#undef 取消已定義的宏#if 如果給定條件為真,則編譯下面代碼#ifdef 如果宏已經(jīng)定義,則編譯下面代碼#ifndef 如果宏沒有定義,則編譯下面代碼#elif 如果前面的#if給定條件不為真,當(dāng)前條件為真,則編譯下面代碼#endif 結(jié)束一個#if #else條件編譯塊#error 停止編譯并顯示錯誤信息一、文件包含#include預(yù)處理指令的作用是在指令處展開被包含的文件。包含可以是多重的,也就是說一個被包含的文件中還可以包含其他文件。標(biāo)準(zhǔn)C編譯器至少支持八重嵌套包含。預(yù)處理過程不檢查在轉(zhuǎn)換單元中是否已經(jīng)包含了某個文件并阻止對它的多次包含。這樣就可以在多次包含同一個頭文件時,通過給定編譯時的條件來達(dá)到不同的效果。例如:#defineAAA#include"t.c"#undefAAA#include"t.c"為了避免那些只能包含一次的頭文件被多次包含,可以在頭文件中用編譯時條件來進(jìn)行控制。例如:/*my.h*/#ifndefMY_H#defineMY_H#endif在程序中包含頭文件有兩種格式:#include<my.h>#include"my.h"第一種方法是用尖括號把頭文件括起來。這種格式告訴預(yù)處理程序在編譯器自帶的或外部庫的頭文件中搜索被包含的頭文件。第二種方法是用雙引號把頭文件括起來。這種格式告訴預(yù)處理程序在當(dāng)前被編譯的應(yīng)用程序的源代碼文件中搜索被包含的頭文件,如果找不到,再搜索編譯器自帶的頭文件。采用兩種不同包含格式的理由在于,編譯器是安裝在公共子目錄下的,而被編譯的應(yīng)用程序是在它們自己的私有子目錄下的。一個應(yīng)用程序既包含編譯器提供的公共頭文件,也包含自定義的私有頭文件。采用兩種不同的包含格式使得編譯器能夠在很多頭文件中區(qū)別出一組公共的頭文件。二、宏宏定義了一個代表特定內(nèi)容的標(biāo)識符。預(yù)處理過程會把源代碼中出現(xiàn)的宏標(biāo)識符替換成宏定義時的值。宏最常見的用法是定義代表某個值的全局符號。宏的第二種用法是定義帶參數(shù)的宏,這樣的宏可以象函數(shù)一樣被調(diào)用,但它是在調(diào)用語句處展開宏,并用調(diào)用時的實(shí)際參數(shù)來代替定義中的形式參數(shù)。#define指令#define預(yù)處理指令是用來定義宏的。該指令最簡單的格式是:首先神明一個標(biāo)識符,然后給出這個標(biāo)識符代表的代碼。在后面的源代碼中,就用這些代碼來替代該標(biāo)識符。這種宏把程序中要用到的一些全局值提取出來,賦給一些記憶標(biāo)識符。#defineMAX_NUM10intarray[MAX_NUM];for(i=0;i<MAX_NUM;i++)/*......*/在這個例子中,對于閱讀該程序的人來說,符號MAX_NUM就有特定的含義,它代表的值給出了數(shù)組所能容納的最大元素數(shù)目。程序中可以多次使用這個值。作為一種約定,習(xí)慣上總是全部用大寫字母來定義宏,這樣易于把程序紅的宏標(biāo)識符和一般變量標(biāo)識符區(qū)別開來。如果想要改變數(shù)組的大小,只需要更改宏定義并重新編譯程序即可。宏表示的值可以是一個常量表達(dá)式,其中允許包括前面已經(jīng)定義的宏標(biāo)識符。例如:#defineONE1#defineTWO2#defineTHREE(ONE+TWO)注意上面的宏定義使用了括號。盡管它們并不是必須的。但出于謹(jǐn)慎考慮,還是應(yīng)該加上括號的。例如:six=THREE*TWO;預(yù)處理過程把上面的一行代碼轉(zhuǎn)換成:six=(ONE+TWO)*TWO;如果沒有那個括號,就轉(zhuǎn)換成six=ONE+TWO*TWO;了。宏還可以代表一個字符串常量,例如:#defineVERSION"Version1.0Copyright(c)2003"帶參數(shù)的#define指令帶參數(shù)的宏和函數(shù)調(diào)用看起來有些相似??匆粋€例子:#defineCube(x)(x)*(x)*(x)可以時任何數(shù)字表達(dá)式甚至函數(shù)調(diào)用來代替參數(shù)x。這里再次提醒大家注意括號的使用。宏展開后完全包含在一對括號中,而且參數(shù)也包含在括號中,這樣就保證了宏和參數(shù)的完整性??匆粋€用法:intnum=8+2;volume=Cube(num);展開后為(8+2)*(8+2)*(8+2);如果沒有那些括號就變?yōu)?+2*8+2*8+2了。下面的用法是不安全的:volume=Cube(num++);如果Cube是一個函數(shù),上面的寫法是可以理解的。但是,因?yàn)镃ube是一個宏,所以會產(chǎn)生副作用。這里的擦?xí)皇呛唵蔚谋磉_(dá)式,它們將產(chǎn)生意想不到的結(jié)果。它們展開后是這樣的:volume=(num++)*(num++)*(num++);很顯然,結(jié)果是10*11*12,而不是10*10*10;那么怎樣安全的使用Cube宏呢?必須把可能產(chǎn)生副作用的操作移到宏調(diào)用的外面進(jìn)行:intnum=8+2;volume=Cube(num);num++;#運(yùn)算符出現(xiàn)在宏定義中的#運(yùn)算符把跟在其后的參數(shù)轉(zhuǎn)換成一個字符串。有時把這種用法的#稱為字符串化運(yùn)算符。例如:#definePASTE(n)"adhfkj"#nmain(){printf("%s\n",PASTE(15));}宏定義中的#運(yùn)算符告訴預(yù)處理程序,把源代碼中任何傳遞給該宏的參數(shù)轉(zhuǎn)換成一個字符串。所以輸出應(yīng)該是adhfkj15。##運(yùn)算符##運(yùn)算符用于把參數(shù)連接到一起。預(yù)處理程序把出現(xiàn)在##兩側(cè)的參數(shù)合并成一個符號。看下面的例子:#defineNUM(a,b,c)a##b##c#defineSTR(a,b,c)a##b##cmain(){printf("%d\n",NUM(1,2,3));printf("%s\n”,STR("aa”,"bb”,"cc"));}最后程序的輸出為:123aabbcc千萬別擔(dān)心,除非需要或者宏的用法恰好和手頭的工作相關(guān),否則很少有程序員會知道##運(yùn)算符。絕大多數(shù)程序員從來沒用過它。三、條件編譯指令條件編譯指令將決定那些代碼被編譯,而哪些是不被編譯的??梢愿鶕?jù)表達(dá)式的值或者某個特定的宏是否被定義來確定編譯條件。#if指令#if指令檢測跟在制造另關(guān)鍵字后的常量表達(dá)式。如果表達(dá)式為真,則編譯后面的代碼,知道出現(xiàn)#else、#elif或#endif為止;否則就不編譯。#endif指令#endif用于終止#if預(yù)處理指令。#defineDEBUG0main(){#ifDEBUGprintf("Debugging\n");#endifprintf("Running\n");}由于程序定義DEBUG宏代表0,所以#if條件為假,不編譯后面的代碼直到#endif,所以程序直接輸出Runningo如果去掉#define語句,效果是一樣的。#ifdef和
溫馨提示
- 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)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度新能源車輛贈予及充電設(shè)施安裝合同3篇
- 中國石化2024年度原料進(jìn)口協(xié)議模板版
- 2025年智能工廠車間場地租賃及維護(hù)服務(wù)合同范本4篇
- 二零二五年院落出租與非物質(zhì)文化遺產(chǎn)保護(hù)合同3篇
- 2025版智能門面房租賃服務(wù)合作協(xié)議4篇
- 2025版海外院校代理傭金合同標(biāo)準(zhǔn)范本4篇
- 二零二五版高速公路監(jiān)控系統(tǒng)光纜安裝合同3篇
- 2025年項(xiàng)目經(jīng)理入職及項(xiàng)目團(tuán)隊激勵方案合同3篇
- 現(xiàn)代醫(yī)療技術(shù)下的疾病預(yù)防策略
- 二零二五版美團(tuán)騎手薪酬福利及晉升體系合同4篇
- 【采購管理優(yōu)化探究文獻(xiàn)綜述3000字】
- 《大學(xué)生職業(yè)發(fā)展與就業(yè)指導(dǎo)》課程標(biāo)準(zhǔn)
- 第23課《出師表》課件(共56張)
- GB/T 3953-2024電工圓銅線
- 發(fā)電機(jī)停電故障應(yīng)急預(yù)案
- 接電的施工方案
- 幼兒阿拉伯?dāng)?shù)字描紅(0-100)打印版
- 社會組織等級評估報告模板
- GB/T 12173-2008礦用一般型電氣設(shè)備
- 新媒體研究方法教學(xué)ppt課件(完整版)
- 2020新版?zhèn)€人征信報告模板
評論
0/150
提交評論