C++中的預編譯

C++提供的編譯預處理功能主要有以下三種:
(一) 宏定義
(二) 文件包含
(三) 條件編譯
預編譯又稱爲預處理 , 是做些代碼文本的替換工作。處理 # 開頭的指令 , 比如拷貝 #include 包含的文件代碼, #define 宏定義的替換 , 條件編譯等,就是爲編譯做的預備工作的階段,主要處理#開始的預編譯指令,預編譯指令指示了在程序正式編譯前就由編譯器進行的操作,可以放在程序中的任何位置。
預處理指令是以#號開頭的代碼行。#號必須是該行除了任何空白字符外的第一個字符。#後是指令關鍵字,在關鍵字和#號之間允許存在任意個數的空白字符。整行語句構成了一條預處理指令,該指令將在編譯器進行編譯之前對源代碼做某些轉換。下面是部分預處理指令:

指令用途

        指令             用途
         #           空指令,無任何效果
         #include    包含一個源代碼文件
         #define     定義宏
         #undef      取消已定義的宏
         #if         如果給定條件爲真,則編譯下面代碼
         #ifdef      如果宏已經定義,則編譯下面代碼
         #ifndef     如果宏沒有定義,則編譯下面代碼
         #elif       如果前面的#if給定條件不爲真,當前條件爲真,則編譯下面代碼
         #endif      結束一個#if……#else條件編譯塊
         #error      停止編譯並顯示錯誤信息

1.宏
C++ 宏定義將一個標識符定義爲一個字符串,源程序中的該標識符均以指定的字符串來代替。因此預處理命令後通常不加分號。這並不是說所有的預處理命令後都不能有分號出現。由於宏定義只是用宏名對一個字符串進行簡單的替換,因此如果在宏定義命令後加了分號,將會連同分號一起進行置換

#define預處理指令是用來定義宏的。該指令最簡單的格式是:首先神明一個標識符,然後給出這個標識符代表的代碼。在後面的源代碼中,就用這些代碼來替代該標識符。這種宏把程序中要用到的一些全局值提取出來,賦給一些記憶標識符。

#define      MIN(A, B)     ((A) <= (B)? (A):(B))

用#define定義函數注意點:
將函數中的參數擴起來

#define ADD(x, y) x + y
#define MUL(x, y) x * y

int main ( int argc, char *argv[] )
{
   int a= 2, b = 3;
   printf ("\nProgram %d\n\n", MUL(ADD(a, b), 5) );  //被轉換成2 + 3 * 5 注意 沒有括號 故結果爲17
   return 0;
} 

用#define來定義函數的優缺點:
優點:可完成函數調用的功能,又能減少系統開銷,提高運行效率。因爲它是在預處理階段即進行了宏展開,在執行時不需要轉換,即在當地執行。
缺點:所佔用的目標代碼空間相對較大
犧牲空間來換取時間

#define具有替代的作用,可以當做是全局變量的使用,在C++中,把一個變量設置成const後,值也是不會再改變,那麼#define和const有什麼區別的呢?

const常量與define宏定義的區別

(1) 編譯器處理方式不同。define宏是在預處理階段展開,生命週期止於編譯期。
只是一個常數、一個命令中的參數,沒有實際的存在。#define常量存在於程序的代碼段。const常量是編譯運行階段使用,const常量存在於程序的數據段.2)類型和安全檢查不同。define宏沒有類型,不做任何類型檢查,僅僅是展開。
const常量有具體的類型,在編譯階段會執行類型檢查。
(3) 存儲方式不同。define宏僅僅是展開,有多少地方使用,就展開多少次,不會分配內存。
const常量會在內存中分配(可以是堆中也可以是棧中)

2.文件包含
#include預處理指令的作用是在指令處展開被包含的文件。包含可以是多重的,也就是說一個被包含的文件中還可以包含其他文件。

在程序中包含頭文件有兩種格式:
    #include <my.h>
    #include "my.h"
第一種方法是用尖括號把頭文件括起來。這種格式告訴預處理程序在編譯器自帶的或外部庫的頭文件中搜索被包含的頭文件。第二種方法是用雙引號把頭文件括起來。這種格式告訴預處理程序在當前被編譯的應用程序的源代碼文件中搜索被包含的頭文件,如果找不到,再搜索編譯器自帶的頭文件。
採用兩種不同包含格式的理由在於,編譯器是安裝在公共子目錄下的,而被編譯的應用程序是在它們自己的私有子目錄下的。一個應用程序既包含編譯器提供的公共頭文件,也包含自定義的私有頭文件。採用兩種不同的包含格式使得編譯器能夠在很多頭文件中區別出一組公共的頭文件
//總之, #include <my.h>是從標準庫路徑中開始搜索文件, #include "my.h"是編譯器從用戶的工作路徑開始搜索文件

3.條件編譯指令
條件編譯指令將決定那些代碼被編譯,而哪些是不被編譯的。可以根據表達式的值或者某個特定的宏是否被定義來確定編譯條件。
1.#if指令
#if指令檢測跟在製造另關鍵字後的常量表達式。如果表達式爲真,則編譯後面的代碼,直到出現#else、#elif或#endif爲止;否則就不編譯。
2.#endif指令
#endif用於終止#if預處理指令。

#define DEBUG 0    //定義了一個宏
main()
   {
        #if DEBUG    //判斷DEBUG的值,雖然已經定義,但是值是0
             printf("Debugging\n");
        #endif   //DEBUG 爲0,endif成立
             printf("Running\n");
    }   
//由於程序定義DEBUG宏代表0,所以#if條件爲假,不編譯後面的代碼直到#endif,所以程序直接輸出Running。如果去掉#define語句,效果是一樣的。

3.#ifdef和#ifndef

 #define DEBUG  //定義了一個宏
 main()
     {
          #ifdef DEBUG   //判斷DEBUG是否定義,#ifdef是定義了
              printf("yes\n");
          #endif
          #ifndef DEBUG   //  判斷DEBUG是否沒定義
               printf("no\n");
          #endif
        }
       // #if defined等價於#ifdef; #if !defined等價於#ifndef

4.#else指令
#else指令用於某個#if指令之後,當前面的#if指令的條件不爲真時,就編譯#else後面的代碼。#endif指令將中指上面的條件塊。

#define DEBUG
main()
    {
       #ifdef DEBUG //是否定義DEBUG
            printf("Debugging\n");
       #else
             printf("Not debugging\n");
       #endif
             printf("Running\n");
       }
    //#else,#elif和endif是一樣的

5.#elif指令
#elif預處理指令綜合了#else和#if指令的作用。

  #define TWO
        main()
        {
            #ifdef ONE
                printf("1\n");
            #elif defined TWO
                printf("2\n");
            #else
                printf("3\n");
            #endif
        }
       // 程序很好理解,最後輸出結果是2。

6.其他一些標準指令
#error指令將使編譯器顯示一條錯誤信息,然後停止編譯。
#line指令可以改變編譯器用來指出警告和錯誤信息的文件號和行號。
#pragma指令沒有正式的定義。編譯器可以自定義其用途。典型的用法是禁止或允許某些煩人的警告信息

發佈了46 篇原創文章 · 獲贊 13 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章