預編譯的不同形式和辨析整理

  預編譯又稱爲預處理,在代碼編寫的過程中是位於編譯之前的。簡單來說可以認爲是做一些代碼文本的替換工作,我們最常見的一種就是宏定義和#include類型,預編譯過程中處理的是#開頭的指令,最常見的預編譯指令有:

一、#include指令

  如果是用<>括起來的文件那麼就在系統的include目錄中尋找文件,如果用""括起來就表示在當前目錄中尋找文件(多是程序員自己編寫),一般來說,多以h或cpp爲後綴,另外需要注意的是如果我們在本應該是include目錄中尋找的文件中(也就是本應該用<>的地方)用了“”,它也會先在當前目錄下搜索文件,再在系統默認目錄下搜索文件。

二、#define指令

  也就是宏定義,最常見的定義常數

  #define a 1

這是最簡單的形式,實際上我們用#define還會用於製造一些“函數”,之所以打引號,也就是說其實宏定義所要表達的雖然是函數的意義,但卻不是C++裏真正的函數,原因是顯而易見的。

函數和宏定義的區別

1) 首先在函數中我們的變量是必須要註明其參數類型的,而在宏定義中其實是簡單的文本替換,專業的說法可以是宏定義經過預處理器的處理,只負責做形式上的轉換,但是不負責做參數類型檢查,這也代表着我們在傳遞參數的時候要做比較細緻的檢查。

2) 其次宏定義用文本替換的手法一定程度上抹殺了他的智能性,這導致我們在書寫宏定義的時候最好在參數兩邊加上括號,某種程度上,這也是必須要加的。舉個非常簡單的例子,比如我們要用宏定義來表達一個乘法“函數”

#define mul(A,B) A*B
int main(){
printf("%d",(1+2,3));
return 0;
}

按照常理結果應該是9,但是事實上因爲乘法的優先級比加法要高,導致的結果就是1+6=7,所以我們有必要在“參數”的兩端加上括號

<pre name="code" class="cpp">#define mul(A,B) (A)*(B) 
int main(){       
printf("%d",(1+2,3));      
return 0;} 
   

但即使是加上了括號,依舊不能避免一些錯誤的發生,比如有a++形式的,可能因爲調用的過程中,盲目的調用a++形式,使得本來程序員只想加一次1,卻加了多次1。

3) 在一些情況中,使用宏定義會導致極低的代碼執行效率,舉例如下

int a[]={9,3,5,2,1,0,8,7,6,4};
int max(n)
{
    return n==0?a[0]:MAX(a[n],max(n-1));
}

int main()
{
    max(9);
    return 0;
}

 我們觀察上面的MAX函數(注意是大寫)如果用宏定義的寫法,那麼宏展開爲( a[n]>max(n-1)?a[n]:max(n-1) ),其中max函數被調用了兩遍使得代碼執行效率大大降低,而如果我們直接用函數的寫法,那麼很簡單,代碼的執行效率是O(n)。

宏定義的一些用法

1) 宏定義的最基本的用法是用來定義常數(略),但是需要注意的一點是,對於同一變量,如果我們重複進行宏定義,那麼最終的結果是最後一次的宏定義的結果;

2) 定義標識,常常與#if #ifdef一起聯用,不管是#if還是#ifdef最後都是以#endif來標識結尾的。下面進行區分#if和#ifdef。

  首先#ifdef(a)的意思表示是對於a是否被宏定義過進行一輪判斷,而#if(a>0)則是表示如果a>0,則執行後面的宏定義內容。相同的是,不管是#if還是#endif,最後都是用#endif來標識一段的結尾,舉個ifdef的例子,如果我們事先進行數據選擇,不同的是一個是windows下的實例,一個是linux下的實例,那麼我們就在不同端的代碼中定義一個宏變量windows,當意識到windows已經被宏定義過後,則加入後續代碼。

  我們可以簡單認爲#ifdef後面接的是一個是否被宏定義的變量,而#if後面則是表達式

#if (MAX==10)||(MAX==20)
 code...
#endif
#ifdef (x)
    ...code...
#endif
3)用於定義一些“函數”



               







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章