1. 程式人生 > >#define、#undef、#ifdef、#ifndef、#if、#elif、#else、#endif、defined

#define、#undef、#ifdef、#ifndef、#if、#elif、#else、#endif、defined

 

 

#define            定義一個預處理巨集
#undef            取消巨集的定義

#if                   編譯預處理中的條件命令,相當於C語法中的if語句
#ifdef              判斷某個巨集是否被定義,若已定義,執行隨後的語句
#ifndef            與#ifdef相反,判斷某個巨集是否未被定義
#elif                若#if, #ifdef, #ifndef或前面的#elif條件不滿足,則執行#elif之後的語句,相當於C語法中的else-if
#else              與#if, #ifdef, #ifndef對應, 若這些條件不滿足,則執行#else之後的語句,相當於C語法中的else
#endif             #if, #ifdef, #ifndef這些條件命令的結束標誌.
defined          與#if, #elif配合使用,判斷某個巨集是否被定義

條件編譯是根據實際定義巨集(某類條件)進行程式碼靜態編譯的手段。可根據表示式的值或某個特定巨集是否被定義來確定編譯條件。

最常見的條件編譯是防止重複包含標頭檔案的巨集,形式跟下面程式碼類似:

1 #ifndef ABCD_H
2 #define ABCD_H
3 
4 // ... some declaration codes
5 
6 #endif // #ifndef ABCD_H

在實現檔案中通常有如下類似的定義:

 1 #ifdef _DEBUG
 2 
 3 // ... do some operations
 4 
 5 #endif
 6 
 7 #ifdef _WIN32
 8 
 9 // ... use  Win32 API
10 
11 #endif

這些都是條件編譯的常用情境。

1. #define、#undef

#define命令定義一個巨集:
#define MACRO_NAME[(args)] [tokens[(opt)]]
之後出現的MACRO_NAME將被替代為所定義的標記(tokens)。巨集可帶引數,而後面的標記也是可選的。

巨集定義,按照是否帶引數通常分為物件巨集、函式巨集兩種。
物件巨集: 不帶引數的巨集被稱為"物件巨集(objectlike macro)"。物件巨集多用於定義常量、通用標識。例如:

// 常量定義
#define MAX_LENGTH 100
// 通用標識,日誌輸出巨集
#define SLog printf
// 預編譯巨集
#define _DEBUG

函式巨集:帶引數的巨集。利用巨集可以提高程式碼的執行效率: 子程式的呼叫需要壓棧出棧, 這一過程如果過於頻繁會耗費掉大量的CPU運算資源。 所以一些程式碼量小但執行頻繁的程式碼如果採用帶引數巨集來實現會提高程式碼的執行效率。但多數c++程式不推薦使用函式巨集,除錯上有一定難度,可考慮使用c++的inline代替之。例如:

// 最小值函式
#define MIN(a,b) ((a)>(b)? (a):(b))
// 安全釋放記憶體函式
#define SAFE_DELETE(p) {if(NULL!=p){delete p; p = NULL;}}

#undef可以取消巨集定義,與#define對應。

2. defined

defined用來測試某個巨集是否被定義。defined(name): 若巨集被定義,則返回1,否則返回0。
它與#if、#elif、#else結合使用來判斷巨集是否被定義,乍一看好像它顯得多餘, 因為已經有了#ifdef和#ifndef。defined可用於在一條判斷語句中宣告多個判別條件;#ifdef和#ifndef則僅支援判斷一個巨集是否定義。

#if defined(VAX) && defined(UNIX) && !defined(DEBUG) 

和#if、#elif、#else不同,#ifdef、#ifndef、defined測試的巨集可以是物件巨集,也可以是函式巨集。

3. #ifdef、#ifndef、#else、#endif

條件編譯中相對常用的預編譯指令。模式如下:

#ifdef ABC
// ... codes while definded ABC
#elif (CODE_VERSION > 2)
// ... codes while CODE_VERSION > 2
#else
// ... remained cases
#endif // #ifdef ABC 

#ifdef用於判斷某個巨集是否定義,和#ifndef功能正好相反,二者僅支援判斷單個巨集是否已經定義,上面例子中二者可以互換。如果不需要多條件預編譯的話,上面例子中的#elif和#else均可以不寫。

4. #if、#elif、#else、#endif

#if可支援同時判斷多個巨集的存在,與常量表達式配合使用。常用格式如下:

#if 常量表達式1
// ... some codes
#elif 常量表達式2
// ... other codes
#elif 常量表達式3
// ...
...
#else
// ... statement
#endif

常量表達式可以是包含巨集、算術運算、邏輯運算等等的合法C常量表達式,如果常量表達式為一個未定義的巨集, 那麼它的值被視為0。

#if MACRO_NON_DEFINED // 等價於

#if 0

在判斷某個巨集是否被定義時,應當避免使用#if,因為該巨集的值可能就是被定義為0。而應當使用#ifdef或#ifndef。
注意: #if、#elif之後的巨集只能是物件巨集。如果巨集未定義,或者該巨集是函式巨集,則編譯器可能會有對應巨集未定義的警告。