
1.預(yù)處理指令
1)C語(yǔ)言在對(duì)源程序進(jìn)行編譯之前,會(huì)先對(duì)一些特殊的預(yù)處理指令作解釋。預(yù)處理過(guò)程掃描源代碼,對(duì)其進(jìn)行初步的轉(zhuǎn)換,產(chǎn)生新的源代碼提供給編譯器。
2)預(yù)處理指令是以#號(hào)開(kāi)頭的代碼行。#號(hào)必須是該行除了任何空白字符外的第一個(gè)字符。#后是指令關(guān)鍵字,在關(guān)鍵字和#號(hào)之間允許存在任意個(gè)數(shù)的空白字符。整行語(yǔ)句構(gòu)成了一條預(yù)處理指令,該指令將在編譯器進(jìn)行編譯之前對(duì)源代碼做某些轉(zhuǎn)換。
3)預(yù)處理指令可以放在文件任何位置,他的作用范圍是從它出現(xiàn)的位置到文件尾,習(xí)慣上我們常把它放在源程序頭部,這樣它的作用范圍就是整個(gè)源程序文件了。
4)預(yù)處理指令可分成三類:宏定義、文件包含、條件編譯
2.宏定義
1)宏定義了一個(gè)代表特定內(nèi)容的標(biāo)識(shí)符。預(yù)處理過(guò)程會(huì)把源代碼中出現(xiàn)的宏標(biāo)識(shí)符替換成宏定義時(shí)的值。
-
2)#define指令: 不帶參數(shù)的宏定義(宏名一般大寫)
- 一般形式:#define 宏名 字符串
#define COUNT 5- 宏表示的值可以是一個(gè)常量表達(dá)式,其中允許包括前面已經(jīng)定義的宏標(biāo)識(shí)符。
#define ONE1 1 #define TWO2 2 #define THREE (ONE+TWO)注意上面的宏定義使用了括號(hào)。盡管它們并不是必須的。但出于謹(jǐn)慎考慮,還是應(yīng)該加上括號(hào)的。
NSInteger six = 0; six = THREE * TWO; //預(yù)處理過(guò)程把上面的一行代碼轉(zhuǎn)換成: six = (ONE+TWO) * TWO; //如果沒(méi)有那個(gè)括號(hào),就轉(zhuǎn)換成 six = ONE+TWO * TWO;- 宏還可以代表一個(gè)字符串常量
#define VERSION "Version1.0 Copyright(c)2003"
-
3)帶參數(shù)的#define指令:帶參數(shù)的宏定義(宏名一般大寫)
- 一般形式:#define 宏名 (參數(shù))
#define Cube (x) (x)*(x)*(x)- 帶參數(shù)的宏和函數(shù)調(diào)用看起來(lái)有些相似。可以是任何數(shù)字表達(dá)式甚至函數(shù)調(diào)用來(lái)代替參數(shù)x。這里再次提醒大家注意括號(hào)的使用。宏展開(kāi)后完全包含在一對(duì)括號(hào)中,而且參數(shù)也包含在括號(hào)中,這樣就保證了宏和參數(shù)的完整性。
NSInteger volume = 0; int num = 8+2; volume = Cube(num); //展開(kāi)后為(8+2)*(8+2)*(8+2) //如果沒(méi)有那些括號(hào)就變?yōu)?+2*8+2*8+2帶參數(shù)的宏比函數(shù)效率高,宏只會(huì)替換數(shù)值(文本對(duì)換)。不計(jì)算,不會(huì)替換雙引號(hào)括住的字符串。
把可能產(chǎn)生副作用的操作移到宏調(diào)用的外面進(jìn)行
NSInteger volume = 0; int num = 8+2; volume = Cube(num++);//不安全的用法 /**展開(kāi)后是這樣的: volume=(num++)*(num++)*(num++); 很顯然,結(jié)果是10*11*12,而不是10*10*10; */ volume = Cube(num);//安全的用法 num++; -
4)#運(yùn)算符
- 出現(xiàn)在宏定義中的#運(yùn)算符把跟在其后的參數(shù)轉(zhuǎn)換成一個(gè)字符串。有時(shí)把這種用法的#稱為字符串化運(yùn)算符。
#define PASTE (n) "hello "#n main() { NSLog(@"%@",PASTE(2018)); //宏定義中的#運(yùn)算符告訴預(yù)處理程序,把源代碼中任何傳遞給該宏的參數(shù)轉(zhuǎn)換成一個(gè)字符串。所以輸出應(yīng)該是hello 2018 } -
5)##運(yùn)算符
- ## 運(yùn)算符用于把參數(shù)連接到一起。預(yù)處理程序把出現(xiàn)在##兩側(cè)的參數(shù)合并成一個(gè)符號(hào)。
#define NUM (a,b,c) a##b##c #define STR (a,b,c) a##b##c main() { NSLog("%ld ",NUM(1,2,3)); NSLog("%@ ",STR("aa","bb","cc")); //輸出結(jié)果為123 aabbcc }- 除非需要或者宏的用法恰好和手頭的工作相關(guān),否則很少有程序員會(huì)知道##運(yùn)算符。絕大多數(shù)程序員從來(lái)沒(méi)用過(guò)它。
3.條件編譯指令
-
條件編譯指令將決定那些代碼被編譯,而哪些是不被編譯的??梢愿鶕?jù)表達(dá)式的值或者某個(gè)特定的宏是否被定義來(lái)確定編譯條件。
-
預(yù)編譯指令中的表達(dá)式與C語(yǔ)言本身的表達(dá)式基本一至.如邏輯運(yùn)算、算術(shù)運(yùn)算、位運(yùn)算等均可以在預(yù)編譯指令中使用。
-
之所以能夠?qū)崿F(xiàn)條件編譯是因?yàn)轭A(yù)編譯指令是在編譯之前進(jìn)行處理的,通過(guò)預(yù)編譯進(jìn)行宏替換、條件選擇代碼段,然后生成最后的待編譯代碼,最后進(jìn)行編譯。
指令用途
#空指令,無(wú)任何效果
#include包含一個(gè)源代碼文件
#define定義宏
#undef取消已定義的宏
#if如果給定條件為真,則編譯下面代碼
#ifdef如果宏已經(jīng)定義,則編譯下面代碼
#ifndef如果宏沒(méi)有定義,則編譯下面代碼
#elif如果前面的#if給定條件不為真,當(dāng)前條件為真,則編譯下面代碼
#endif結(jié)束一個(gè)#if……#else條件編譯塊
#error停止編譯并顯示錯(cuò)誤信息
編譯方法
- #if ... #elif ... #else ... #endif
#if 條件 1
代碼段 1
#elif 條件 2
代碼段 2
...
#elif 條件 n
代碼段 n
#else
代碼段 n+1
#endif
#if的一般含義是,如果#if后面的常量表達(dá)式為true,則編譯它所控制的代碼.
如果條件1成立時(shí)就代碼段1,條件1不成立再看條件2是否成立;如果條件2成立則編譯代碼段2,否則再依次類推判斷其它條件;如果條件1-N都不成力則會(huì)編譯最后的代碼段n+1.
務(wù)必不能忘了#endif
- #ifdef ... #else ... #endif或#ifndef ... #else ... #endif
#ifdef macro_name
代碼段 1
#else
代碼段 2
#endif
#ifndef macro_name
代碼段 1
#else
代碼段 2
#endif
#ifdef指令與#ifndef指令,它們分別表示“如果有定義”及“如果無(wú)定義”。
有定義是指在編譯此段代碼時(shí)是否有某個(gè)宏通過(guò) #define指令定義的宏,#ifndef指令指找不到通過(guò)#define定義的某宏
該宏可以是在當(dāng)前文件此條指令的關(guān)面定義的,也可以是在其它文件中,但在此指令之前包含到該文件中的。
-
#ifdef指令與#if defined()用法一致
#if defined (宏) 代碼. #endif- 這個(gè)#if后面接的是一個(gè)宏,意思是前面的宏定義里面有沒(méi)有定義這個(gè)宏,如果定義了,編譯器就會(huì)編譯中間的代碼,如果沒(méi)有定義,那就不會(huì)編譯,不管這個(gè)宏定義的是什么東西,對(duì)不對(duì)等
#ifndef指令與if !defined()用法一致(取反的意思)
3、defined(macro_name)
參數(shù)為宏名(無(wú)需加""),如果該macro_name定義過(guò)則返回真,否則返回假
用該函數(shù)則可以寫比較復(fù)雜的條件編譯指令
#if defined(macro1) || (!defined(macro2) && defined(macro3))
...
#else
...
#endif