一、 內容概述
本文主要介紹c語言中條件編譯相關的預編譯指令,包括#define、#undef、#ifdef、#ifndef、#if、#elif、#else、#endif、defined。
二、條件編譯
條件編譯是根據實際定義宏(某類條件)進行代碼靜態編譯的手段。可根據表達式的值或某個特定宏是否被定義來確定編譯條件。
最常見的條件編譯是防止重復包含頭文件的宏,形式跟下面代碼類似:
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
這些都是條件編譯的常用情境。
三、條件編譯中使用的預編譯指令
#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. #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之后的宏只能是對象宏。如果宏未定義,或者該宏是函數宏,則編譯器可能會有對應宏未定義的警告。
五、總結
本文主要介紹c語言中有關預編譯的指令。撰寫本文的目的在於理清相關概念調用,在后續預編譯使用時可以找到最合適的指令及格式。比如同時滿足多個宏定義的預編譯、多分支預編譯、#elif和#else指令的配合等。
參考資料:
Preprocessor Directives http://msdn.microsoft.com/zh-cn/library/aa381033