有些程式在調試、相容性、平台移植等情況下可能想要通過簡單地設定一些參數就產生一個不同的軟體,這當然可以通過變數設定,把所有可能用到的代碼都寫進去,在初始化時配置,但在不同的情況下可能只用到一部分代碼,就沒必要把所有的代碼都寫進去,就可以用條件編譯,通過先行編譯指令設定編譯條件,在不同的需要時編譯不同的代碼。
(一)條件編譯方法
條件編譯是通過先行編譯指令來實現的,主要方法有:
1、#if, #elif, #else, #endif
#if 條件 1
程式碼片段 1
#elif 條件 2
程式碼片段 2
...
#elif 條件 n
程式碼片段 n
#else
程式碼片段 n+1
#endif
即可以設定不同的條件,在編譯時間編譯不同的代碼,先行編譯指令中的運算式與C語言本身的運算式基本一至如邏輯運算、算術運算、位元運算等均可以在先行編譯指令中使用。之所以能夠實現條件編譯是因為先行編譯指令是在編譯之前進行處理的,通過先行編譯進行宏替換、條件選擇程式碼片段,然後產生最後的待編譯代碼,最後進行編譯。
#if的一般含義是,如果#if後面的常量運算式為true,則編譯它所控制的代碼,如條件1成立時就程式碼片段1,條件1不成立再看條件2是否成立,如果條件2成立則編譯程式碼片段2,否則再依次類推判斷其它條件,如果條件1-N都不成力則會編譯最後的程式碼片段n+1.
2、#ifdef, #else, #endif或#ifndef, #else, #endif
條件編譯的另一種方法是用#ifdef與#ifndef命令,它們分別表示“如果有定義”及“如果無定義”。有定義是指在編譯此段代碼時是否有某個宏通過 #define 指令定義的宏,#ifndef指令指找不到通過#define定義的某宏,該宏可以是在當前檔案此條指令的關面定義的,也可以是在其它檔案中,但在此指令之前包含到該檔案中的。
#ifdef的一般形式是:
#ifdef macro_name
程式碼片段 1
#else
程式碼片段 2
#endif
或
#ifdef的一般形式是:
#ifndef macro_name
程式碼片段 2
#else
程式碼片段 1
#endif
這兩段代碼的效果是完全一樣的。
3、通過宏函數defined(macro_name)
參數為宏名(無需加""),如果該macro_name定義過則返回真,否則返回假,用該函數則可以寫比較複雜的條件編譯指令如
#if defined(macro1) || (!defined(macro2) && defined(macro3))
...
#else
...
#endif
(二)條件編譯技巧與樣本
(1)#ifdef和#defined()比較
首先比較一下這兩種方法,第一種方法只能判斷一個宏,如果條件比較複雜實現起來比較煩鎖,用後者就比較方便。如有兩個宏MACRO_1,MACRO_2隻有兩個宏都定義過才會編譯程式碼片段A,分別實現如下:
#ifdef MACRO_1
#ifdef MACRO_2
程式碼片段 A
#endif
#endif
或者
#if defined(MACRO_1) && defined(MACRO_2)
#endif
同樣,要實現更複雜的條件用#ifdef更麻煩,所以推薦使用後者,因為即使當前代碼用的是簡單的條件編譯,以後在維護、升級時可能會增加,用後者可維護性較強。舊的編譯器可能沒有實現#defined()指令,C99已經加為標準。要相容老的編譯器,還需用#ifdef指令。
2、#if與 #ifdef或#if defined()比較
比如自己寫了一個printf函數,想通過一個宏MY_PRINTF_EN實現條件編譯,用#if可實現如下
#define MY_PRINTF_EN 1
#if MYS_PRINTF_EN == 1
int printf(char* fmt, char* args, ...)
{
...
}
#endif
如果宏MY_PRINTF_EN定義為1則編譯這段代碼,如果宏定義不為1或者沒有定義該宏,則不編譯這段代碼。同樣也可以通過#ifdef或者#defined()實現,如
#define MY_PRINTF_EN 1
#if defined(MY_PRINTF_EN)
int printf(char* fmt, char* args, ...)
{
...
}
#endif