眾所周知,你的程式編譯前要做的事就是掃瞄源**,對其做初步的轉換,產生新的源**提供給編譯器,這個過程就叫編譯預處理。這個處理過程由預處理器來完成,預處理器是在程式真正執行前由編譯器呼叫的預處理程式。
常見的預處理有以下三種:
檔案包含:#include 是一種最為常見的預處理,主要是做為檔案的引用組合源程式正文。
巨集替換: #define,這是最常見的用法,它可以定義符號常量、函式功能、重新命名、字串的拼接等各種功能。
條件編譯:#if,#ifndef,#ifdef,#elif,#endif,#undef等也是比較常見的預處理,主要是進行編譯時進行有選擇的挑選,注釋掉一些指定的**,以達到版本控制、防止對檔案重複包含的功能。
一,檔案包含
#include預處理指令的作用是在指令處展開被包含的檔案。包含可以是多重的,也就是說乙個被包含的檔案中還可以包含其他檔案。預處理器至多支援15層巢狀包含。
預處理過程不檢查在轉換單元中是否已經包含了某個檔案並阻止對它的多次包含。這樣就很容易發生相同的乙個檔案被包含多次的情況,可以輕易地利用條件式編譯的預處理指令避免多次包含相同的檔案,例如:
[cpp]view plain
copy
/*incfile.h*/
#ifndef incfile_h_
#define incfile_h_
/*...incfile.h實際的內容寫在這裡...*/
#endif
檔案包含中的<>和" ""的區別就不用說了。
二,巨集
可以利用預處理指令#define來定義巨集。使用預處理指令可以把乙個名稱指定成任何文字,例如常量值或者語句。當定義巨集後,並且此巨集的名稱出現在源**中,預處理器就會把它替換掉。
由於巨集替換是簡單的替換,所以在定義巨集的時候務必要加(),如:
#define max(x,y) ((x)>(y))?(x):(y)
在巨集中還有兩類重要的運算子:字串化運算子和「貼上記號」運算子
單元運算子#常常被稱為字串化運算子(stringizing operator),因為它會把乙個巨集引數轉換為字串。#的運算元必須是「巨集替代文字」中的引數arg,當引數名稱出現在替代文字中,並且前置#字元時,預處理器會把對應的自變數放在一對引號中,形成乙個字串字面值。如下所示:
[cpp]view plain
copy
#define printangle(arg) printf(#arg " = %f",arg)
int main()
上面程式的輸出是:3 *0.5 = 1.500000
##運算子是乙個二元運算子,可以出現在任何巨集的替代文字中。此運算子會把左和右運算元結合咋i一起,稱為乙個記號,常常被稱為「貼上記號」運算子。如下所示:
[cpp]view plain
copy
#define text "hello,world,"
#define msg(x) puts(text ## x)
int main()
上面程式的輸出是: hello,world, it's cobing
如果不顯示地取消巨集的定義,巨集的作用域是全域性的,即當前編譯單元內所有的檔案都是可見的。可以用#undef macro_name 來取消巨集定義
三條件編譯
條件式編譯區域始於#if, #ifdef或#ifndef等預處理指令,結束於#endif預處理指令。條件式編譯區域內可以有任意數目的#elif預處理指令,以及最多乙個#else預處理指令,以#if開始的條件式編譯區域具有下面的格式:
#if expression1
[group1 ]
[#elif expression2
[group2 ]]
...[#elif expression3
[group3 ]]
[#else
[group(n+1) ]]
#endif
預處理器會依序計算條件表示式,直到發現某個結果非0的表示式。預處理器會保留對應group內的源**,共後續處理。在預處理器結束時,預處理器會刪除程式中沒有被保留的group。下面是乙個例項**
[cpp]view plain
copy
#if defined(__unix__) && defined(__gnuc__)
/*...*/
#endif
#ifdef和#ifndef預處理指令可以測試是否某個巨集被定義
[c-sharp]view plain
copy
#ifndef macro_a
#define macro_a
/*...*/
#endif
#error預處理指令會讓預處理器發出錯誤資訊:
#error [text]
如果可選性的text出現,這段文字就會被包含在預處理器中有關該錯誤的錯誤資訊中。然後編譯器會停止處理源**,並結束施行,彷彿遇到了嚴重的錯誤。
[c-sharp]view plain
copy
#ifndef lex
#error "lex is not defined"
#endif
如果lex未被定義,上面的程式編譯不成功,編譯器提示"fatal error:lex is not defined"
C C 編譯預處理指令
眾所周知,你的程式編譯前要做的事就是掃瞄源 對其做初步的轉換,產生新的源 提供給編譯器,這個過程就叫編譯預處理。這個處理過程由預處理器來完成,預處理器是在程式真正執行前由編譯器呼叫的預處理程式。常見的預處理有以下三種 include 是一種最為常見的預處理,主要是做為檔案的引用組合源程式正文。巨集替...
C C 預處理指令
預處理指令是以 號開頭的 行。號必須是該行除了任何空白字元外的第乙個字元。後是指令關鍵字,在關鍵字和 號之間允許存在任意個數的空白字元。整行語句構成了一條預處理指令,該指令將在編譯器進行編譯之前對源 做某些轉換。1.和 1 define pi 3.1415926 2 define paste n a...
C C 預處理指令
預處理指令 preprocessor directives define undef ifdef ifndef if endif else and elif line error include 預定義識別符號 pragma 預處理指令是我們寫在程式 中的給預處理器 preprocessor 的命令...