編譯預處理是在編譯源程式之前,由預處理器對源程式進行加工處理工作,所謂預處理器,是包含在編譯器中的預處理程式。如圖所示:
源程式的中的編譯預處理命令一律以#開頭,回車鍵結束,每條命令佔一行,並且通常放在源程式的開始部分。
編譯預處理的作用是將源程式檔案中的預處理命令進行處理,生成乙個中間檔案,編譯系統再對此中間檔案進行編譯並生成目標**,最後生成的目標**中不含有預處理命令;
c++提供的預處理功能主要有巨集定義、檔案包含、條件編譯,前兩種比較常見,主要介紹最後一種
用乙個指定的識別符號來代表乙個字串,這個指定的識別符號稱為巨集名,格式:
#define
《巨集名》 《字串》
#define pi 3.1415926
/**1.在進行預編譯後,將程式中的所有巨集名pi替換成3.1415926
*2.#define 定義的巨集有效範圍為定義處至本原始檔結束,可以使用undef 命令終止巨集定義的作用域
*3.巨集定義語句的行末一般不加分號,因為他僅具有替換功能,並不是**語句
*/#define pi 3.1415926
/* //do something;
*/#undef pi
//終止巨集定義的作用域
巨集名也可以帶引數定義,支援引數替換,其格式為:
#define
《巨集名(引數列表)> 《字串》
#define s(a,b) a*b
/**參數列中的引數a,b稱為巨集名的形式引數,源程式語句中的巨集名仍使用右端字串替換,只不過替換時將字串中的
*形式引數用語句中巨集名所帶的實際引數取代而已;
*/double area;
area=s(
3,2)
;/*此時,3為a的實際引數,2為b的實際引數,則巨集名s(3,2)經處理後,用字串3*2替換再進行編譯。即s(a,b)等同於a*b*/
/*帶引數的巨集替換過程可描述過程如下:*/
按#define命令列中指定的字串從左至右置換巨集名,字串中的形參以相應的實參代替,字串中非形參字元保持不變。
巨集定義是編譯預處理,計算機還未正式編譯程式,就先處理預處理命令,因此,巨集定義的實參對形參的代入是「機械」替換,同時巨集定義的形參也不需要標註資料型別,因為系統這時候還根本不「認識」這些引數的型別,不進行語法檢查,跟談不上為其分配記憶體單元。
函式呼叫是在程式已經編譯連線成為二進位製碼可執行程式後,在執行這個函式時發生的,此時需要分配形參的儲存單元,完成實參到形參的具體值的傳遞,所以函式的形參要定義資料型別,且有時函式需要返回乙個具體的值,函式也需要有明確的型別說明。
巨集定義在程式執行期間時已經不存在了,所以其目的僅僅是為了書寫時使程式清晰、簡潔。巨集展開只占用編譯時間,不占用執行時間,巨集展開後使源程式增長,占用程式的「空間」
被調函式無論被呼叫了多少次,其生成的機器**長度是不變的。但當程式執行時,每次呼叫該函式時,系統都要完成呼叫前的準備和收尾工作,如分配形參單元,儲存呼叫時刻現場位址、引數、值傳遞、函式值返回、恢復現場,這些工作都要占用一定的執行時間,因此函式呼叫占用程式的「時間」
檔案包含用#include命令,預處理後將指令中指明的源程式檔案嵌入到當前原始檔的指令位置處,格式為:
#include
《檔名》
//or
#include
"檔名"
含有檔案包含命令的源程式,在編譯預處理時將所包含的檔案全部內容複製到該命令列處,生成乙個中間檔案,然後編譯連線這個檔案,得到實際上包含兩個(或多個)源程式的可執行程式。
注意:1.乙個#include命令只能包含乙個檔案。
2.檔案包含命令所包含的檔案必須是文字檔案(ascii)檔案,一般是c++原始檔或系統庫檔案,不可以是可執行程式(.exe)或者是目標程式(.obj)
檔案包含有兩種格式,用#include《檔名》的格式時,預處理編譯器就直接到存放c++系統的檔案目錄中查詢要包含的檔案,若找不到,編譯系統給出出錯資訊
。一般來說系統的標準標頭檔案和庫檔案都是用這種方式包含的,如#include。
用#include"檔名"的格式時,預編譯處理器首先在當前編譯檔案所在目錄進行搜尋,如果找不到,再去c++系統目錄中進行搜尋;也可以在包含命令中指定首先搜尋的目錄,如#include"/home/.../file2.cpp",可指定在"/home/.../"目錄下搜尋file2.cpp,若找不到,再去c++系統目錄下搜尋;如果還找不到,就給出出錯資訊。
《一般這種方式用來包含使用者自己建立的檔案》
1.用#include"檔名"的格式時,預編譯處理器首先在當前編譯檔案所在目錄進行,或給定目錄進行搜尋,如果找不到,再去c++系統目錄**中進行搜尋,如果還找不到,就給出出錯資訊。
2.用#include《檔名》的格式時,預處理編譯器就直接到存放c++系統的檔案目錄中查詢要包含的檔案,若找不到,編譯系統給出出錯資訊`。
在通常情況下,源程式中所有的語句都要被編譯,生成機器碼可執行程式。但有時希望源程式的某些語句在滿足一定條件下才被編譯,或者說對源程式的部分語句有選擇進行編譯。
條件編譯指令有兩類:
一是根據巨集名是否定義來確定是否編譯某些程式段;另一類是根據表示式的值來確定被編譯的程式段;
#ifdef 巨集名
程式段1
程式段2
>
#endif
/*#ifdef 與ifndef 作用一樣,只是選擇的條件相反*/
其中<>中的內容可以省略。
如果源程式前面的定義了巨集名,則編譯程式段1,否則編譯程式段2;
例如,在除錯程式時,常常需要輸出一些變數在程式執行過程中的值,以此來檢查程式執行中的錯誤,而除錯完成後不需要輸出這些資訊,就可以將輸出這些值的語句段作為條件語句;
#include
using
namespace std;
intmain()
#define debug
//定義了巨集名debug
cout <<
"n="
<< s << endl;
return0;
}
輸出:
i=0 s=0
i=1 s=0
i=2 s=0
i=3 s=0
i=4 s=0
n=0
#include
using
namespace std;
intmain()
//#define debug //注釋該行,即該行不成立
cout <<
"n="
<< s << endl;
return0;
}
輸出:
n=0
#ifdef 表示式
程式段1
程式段2
>
#endif
其中<>中的內容可以省略。
如果表示式的值非0(表示式應該是一些常量的計算),則編譯程式段1,否則編譯程式段2;
#include
using
namespace std;
intmain()
cout <<
"n="
<< s << endl;
return0;
}
編譯預處理
所謂編譯預處理,就是在c源程式的編譯之前,由編譯預處理程式對這些編譯預處理命令進行處理的過程。最常見的就是常量的替換。編譯預處理按功能可以分為巨集定義,檔案包含和條件編譯三類。編譯預處理命令以 開頭,下面進行詳細說明 一.巨集定義與符號常量 1.無參巨集定義 define 識別符號 字串 1 巨集名...
編譯預處理
1.巨集定義指令 1 定義變數與命令 避免幻數 在巨集定義命名時,盡量能清楚的表明功能,大寫 不能以 開頭易與內建巨集衝突 2 定義巨集函式 define max a,b a b a b int num max 6,5 6 5 6 5 用編譯時間換記憶體空間的是巨集函式 用記憶體空間換執行空間的是內...
編譯預處理
1 定義常量與命令 避免幻數 定義巨集時,避免以 開頭,以防與內建巨集定義衝突。巨集和列舉的區別 a.列舉常量是實體常量中的一種,但巨集不是實體 b.列舉常量屬於常量,但巨集不是常量 c.列舉常量具有型別,但巨集沒有型別。列舉型別主要用於限制性輸入,巨集只是預處理替換符 d.列舉只可以表示整型,巨集...