我們知道在編譯過程中的預處理階段會進行標頭檔案展開,巨集替換以及條件編譯。
1.標頭檔案展開:
首先是標頭檔案展開,標頭檔案的前面都有#符號,其實是理指令。
理指令是以#號開頭的**行。#號必須是該行除了任何空白字元外的第乙個字元。#後是指令關鍵字,在關鍵字和#號
之間允許存在任意個數的空白字元。整行語句構成了一條預處
理指令,該指令將在編譯器進行編譯之前對源**做某
些轉換。下面是部分預處理指令:
# 空指令,無任何效果
#include 包含乙個源**檔案
#define 定義巨集
#undef 取消已定義的巨集
#if 如果給定條件為真,則編譯下面**
#ifdef 如果巨集已經定義,則編譯下面**
#ifndef 如果巨集沒有定義,則編譯下面**
#elif 如果前面的#if給定條件不為真,當前條件為真,則編譯下面**,其實就是else if的簡寫
#endif 結束乙個#if……#else條件編譯塊
#error 停止編譯並顯示錯誤資訊
2.巨集定義:
巨集定義了乙個代表特定內容的識別符號。預處理過程會把源**中出現的巨集識別符號替換成巨集定義時的值。巨集最常見的用
法是定義代表某個值的全域性符號。
巨集的第二種用 法是定義帶引數的巨集(巨集函式),這樣的巨集可以象函式一樣被呼叫,但它是在呼叫語句處展開巨集,並用
呼叫時的實際引數來代替定義中的形式引數。
像這樣#define max(a,b) a> b?a:b 就是定義了乙個巨集函式。
巨集函式與自定義函式相比:巨集函式可以省去分配和釋放棧幀,傳參,傳返回值等一系列工作,因此那些簡短並且被頻
繁呼叫的函式可以用函式式巨集定義來代替實現。
但是巨集函式發生在預處理階段,只進行盲目替換,不進行語法檢查,所以容易出錯,而且不能實現一些複雜的功能。
一些內建巨集定義:
__func__ 顯示這行**所在函式的函式名
__line__ 顯示行號
__time__ 顯示當前時間
__date__ 顯示當前日期
3.條件編譯:
條件編譯我們會經常看到這樣的一些指令如:#if #endif #else #elif等等。
我們需要掌握#ifdef和#ifndef指令。
這二者主要用於防止標頭檔案重複包含帶來的重複定義。我們一般在.h標頭檔案前面加上這麼一段:
//標頭檔案防止重複包含
#ifndef funca_h
#define funca_h
//標頭檔案內容
#end if
這樣,如果a.h包含了funca.h,b.h包含了a.h、funca.h,重複包含,會出現一些type redefination之類的錯誤。
#if defined等價於#ifdef; #if !defined等價於#ifndef
編譯預處理
所謂編譯預處理,就是在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.列舉只可以表示整型,巨集...