複製鏈接
請複製以下鏈接發送給好友

預編譯

鎖定
預編譯是做些代碼文本的替換工作。是整個編譯過程的最先做的工作。
中文名
預編譯
外文名
Precompiling
別    名
又稱為預處理
釋    義
是做些代碼文本的替換工作
編譯指令
編譯器進行的操作

預編譯介紹

預編譯是做些代碼文本的替換工作。
處理以# 開頭的指令 , 比如拷貝 #include 包含的文件代碼,#define 宏定義的替換 , 條件編譯等,就是為編譯做的預備工作的階段。
主要處理#開始的預編譯指令,預編譯指令指示了在程序正式編譯前就由編譯器進行的操作,可以放在程序中的任何位置。
C 編譯系統在對程序進行通常的編譯之前,首先進行預處理 [1] 

預編譯預處理功能

c 提供的預處理功能主要有以下三種:
1 )宏定義。
2 )文件包含。
3 )條件編譯。

預編譯何時需要預編譯

  • 總是使用不經常改動的大型代碼體。
  • 程序由多個模塊組成,所有模塊都使用一組標準的包含文件和相同的編譯選項。在這種情況下,可以將所有包含文件預編譯為一個“預編譯頭”

預編譯編譯指令

預編譯指令指示了在程序正式編譯前就由預編譯器進行的操作,可以放在代碼中任意行,一條預編譯指令佔用一行。常見的預編譯指令有:
(1)#include 指令
該指令指示編譯器將xxx.xxx文件的全部內容插入此處。若用<>括起文件則在系統的INCLUDE目錄中尋找文件,若用" "括起文件則在當前目錄中尋找文件。一般來説,該文件是後綴名為"h"或"hpp"的頭文件。
注意:<>不會在當前目錄下搜索頭文件,如果我們不用<>而用""把頭文件名擴起,其意義為先在當前目錄下搜索頭文件,再在系統默認目錄下搜索。
(2)#define指令
該指令有三種用法:
第一種是定義標識,標識有效範圍為本翻譯單元本指令之後,形如#define XXX,常與#if配合使用;
第二種是定義常數,如#define max 100,則max代表100(這種情況下使用const定義常數更好,原因見注1);
第三種是定義"函數",如#define get_max(a, b) ((a)>(b)?(a):(b)) 則以後使用get_max(x,y)就可以得到x和y中較大的數(這種方法存在一些弊病,見注2)。
第四種是定義"宏函數",如#define GEN_FUN(type) type max_##type(type a,type b){return a>b?a:b;} ,使用時,用GEN_FUN(int),則此處預編譯後就變成了 max_int(int a,int b){return a>b?a:b;},以後就可以使用max_int(x,y)就可以得到x和y中較大的數.比第三種,增加了類型的説明。
(3)#if、#else和#endif指令
這些指令一般這樣配合使用:
#if defined(標識) //如果定義了標識
要執行的指令
#else
要執行的指令
#endif
在頭文件中為了避免重複調用(比如説兩個頭文件互相包含對方),常採用這樣的結構:
#if !(defined XXX) //XXX為一個在你的程序中唯一的標識符
//每個頭文件的標識符都不應相同。
//起標識符的常見方法是若頭文件名為"abc.h"
//則標識為"abc_h"
#define XXX
真正的內容,如函數聲明之類
#endif
注1:因為:const常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查,而對後者只進行字符替換,沒有類型安全檢查,並且在字符替換時可能會產生意料不到的錯誤(邊際效應)。
注2:例如get_max(a++, b)時,a++會被執行多少次取決於a和b的大小!所以建議還是用內聯函數而不是這種方法提高速度。雖然有這樣的弊病,但這種方法的確非常靈活,因為a和b可以是各種數據類型。
注3:可以查看百度百科的預處理命令,編排的比較簡明。
參考資料
  • 1.    李剛, 丁佳, 梁盟磊, et al. 安全編碼預編譯器的設計與實現[J]. 計算機工程, 2011, 37(3):230-232.