7.3 條件編譯命令
在一般情況下,來源程式的所有程式行都會參加編譯,以產生目標代碼。但在某些特殊情況下,也許只希望對部分滿足條件的程式行進行編譯,這就是條件編譯。
程式員可在偵錯工具中增加一些調試語句,以達到跟蹤的目的。當程式調試好後,再利用條件編譯重新編譯,使調試語句不參與編譯,以產生高效的代碼。
常用的條件編譯命令有如下三種格式:
1.格式一
#ifdef <標識符>
程式段1
#else
程式段2
#endif
其中,ifdef、else和endif都是關鍵字。<程式段1>和<程式段2>由若干條預先處理命令或C++語句組成。該條件編譯命令的功能是:如果在程式中定義了指定的<標識符>時,就用<程式段1>參與編譯;否則,用<程式段2>參與編譯。
如果在該格式中省略else分支,也可直接寫為如下形式:
#ifdef <標識符>
程式段
#endif
2.格式二
#ifndef <標識符>
程式段1
#else
程式段2
#endif
或者
#ifndef <標識符>
程式段
#endif
其中,ifndef、else和endif都是關鍵字。該條件編譯命令的功能是:如果在程式中末定義<標識符>時,就用<程式段1>參與編譯;否則,用<程式段2>參與編譯。
3.格式三
#if <常量運算式1>
程式段1
#elif <常量運算式2>
程式段2
……
……
#elif <常量運算式n>
程式段n
#else
程式段n+1
#endif
其中,if、elif、else和endif都是關鍵字。該條件編譯命令的功能是:依次計算常量運算式的值,當為邏輯真時,則用相應的程式段參與編譯;如果全部常量運算式的值都為邏輯假,則用else後的程式段參與編譯。
Visual C++還提供一種類似於函數的運算子defined(),它的格式如下:
defined( <標識符> )
其功能是:當<標識符>已被定義且沒有被取消時,其運算式的值為非0;當<標識符>末定義或已被取消時,其運算式的值為0。它經常被用來判斷某個標識符是否已宏定義。
條件編譯在程式設計中具有十分廣泛的應用。例如,在程式調試時,經常需要在來源程式中插入一些程式調試語句(主要是一些條件判斷語句和輸出語句)。這些語句是為了協助程式調試而插入的,在調試完成後還需要逐一刪除。如果用手工刪除就顯得比較麻煩,而且容易出錯。這時,可以用條件編譯命令來實現自動處理,其代碼如下:
#define DEBUG 1
……
……
#if DEBUG
cout << "OK!"<<endl;
#endif
……
……
#if DEBUG
if (x<0)
cout << "Error : x < 0 "<<endl;
#endif
……
……
在該例中,#if和#endif之間的程式段是專門用於程式調試的。當程式調試完成後,應取消這些語句。這時,可將DEBUG的宏定義改為:
#define DEBUG 0
則在重新編譯時間,由於運算式為邏輯假,因此原#if和#endif之間的調試用程式段將不再參與編譯。
在標頭檔“assert.h”中定義的宏assert可用來測試運算式的值。如果運算式的值為0,則assert就輸出錯誤報表,並調用通過函數庫stdlib.h中的函數abort終止程式的執行。
assert是一個十分有用的調試工具,可用於測試一個變數是否具有某個正確的值。例如,假定程式中的變數應該大於10,那麼可用assert測試x的值,並在x的值不正確時輸出錯誤報表。所用的語句為:
assert( x <=10 );
在遇到這條語句時,如果x大於10,那麼就會列印出包含行號和檔案名稱的錯誤報表並終止該程式的執行。這樣,程式員就可以把查錯的重點放在相關代碼上。
如果定義了符號常量NDEBUG,其後的assert將被忽略。因此,如果不再需要assert時,可把程式碼:
#define NDEBUG
插入來源程式中。而無需手工刪除assert。
例如,在申請動態記憶體時。。。。。
assert assert