IOS開發(fā)之路--C語言預(yù)處理
概述
大家都知道一個C程序的運行包括編譯和鏈接兩個階段,其實在編譯之前預(yù)處理器首先要進行預(yù)處理操作,將處理完產(chǎn)生的一個新的源文件進行編譯。由于預(yù)處理指令是在編譯之前就進行了,因此很多時候它要比在程序運行時進行操作效率高。在C語言中包括三類預(yù)處理指令,今天將一一介紹:
宏定義 條件編譯 文件包含
宏定義
對于程序中經(jīng)常用到的一些常量或者簡短的函數(shù)我們通常使用宏定義來處理,這樣做的好處是對于程序中所有的配置我們可以統(tǒng)一在宏定義中進行管理,而且由于宏定義是在程序編譯之前進行替換相比定義成全局變量或函數(shù)效率更高。
// // main.c // Pretreatment // // Created by Kenshin Cui on 14-6-28. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #include <stdio.h> #define PI 3.14 //宏定義一般大寫 #define R 10 #define S 2*PI*R //在另一個宏里面引用了上面的宏 int main(int argc, const char * argv[]) { float r=10.5; double area=PI*r*r; printf("area=%.2f\n",area); double a=S; printf("a=%.2f\n",a); printf("PI=3.14\n");//注意輸出結(jié)果不是3.14=3.14而是PI=3.14,字符串中的PI并不會被替換 #undef PI //強制終止宏定義,否則它的范圍一直到文件結(jié)束 int PI=3.1415926; double area2=PI*r*r; printf("area2=%.2f\n",area2); return 0; }
宏定義實際的操作就是在預(yù)處理時進行對應(yīng)替換,這個階段不管語法是否正確,而且對于字符串中出現(xiàn)的宏名不會進行替換。宏定義的功能事實上是非常強大的,除了簡單的常量替換還可以傳入?yún)?shù):
// // 1.2.c // Pretreatment // // Created by Kenshin Cui on 14-7-17. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #include <stdio.h> #define SUM(a,b) a+b #define SUB(a,b) (a-b) #define MUL (a,b) (a*b) //這么定義是錯誤的,預(yù)處理器會認為宏名為”MUL“,替換內(nèi)容為”(a,b) (a*b)“ int main(int argc, const char * argv[]) { int a=2,b=3,c,d; c=SUM(a, b); printf("c=%d\n",c); //結(jié)果:c=5 d=SUM(a, b)*2; printf("d=%d\n"); //結(jié)果:8,為什么不是10呢?因為替換后:d=a+b*2也就是2+3*2=8 int e=SUB(b, a)*2; printf("(b-a)*2=%d\n",e); //結(jié)果:2,如果SUB定義時不加括號這里應(yīng)該是-1 return 0; }
上面我們可以看出帶參數(shù)的宏功能很強大,有點類似于函數(shù),同函數(shù)不同的是它只是簡單的替換,不涉及存儲空間分配,參數(shù)、返回值等問題,但是由于它在預(yù)處理階段展開,所以一般效率較高。使用帶參數(shù)的宏需要注意的就是結(jié)果最好用括號括起來否則很容易出現(xiàn)問題(在上面的SUM例子中我們應(yīng)該已經(jīng)看到了);還有一點就是帶參數(shù)的宏定義時名稱和參數(shù)之間不要有空格。
條件編譯
條件編譯其實就是在編譯之前預(yù)處理器根據(jù)預(yù)處理指令判斷對應(yīng)的條件,如果條件滿足就將對應(yīng)的代碼編譯進去,否則代碼就根本不進入編譯環(huán)節(jié)(相當(dāng)于根本就沒有這段代碼)。
// // main.c // Pretreatment // // Created by Kenshin Cui on 14-06-28. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #include <stdio.h> #define COUNT 1 int main(int argc, const char * argv[]) { //判斷是否定義了 COUNT 宏 #if defined(COUNT) //等價于:#ifdef COUNT,相反如果判斷沒有定義過則可以通過#if !defined(COUNT)或者#ifndef COUNT printf("COUNT defined\n"); #endif //判斷宏定義COUNT是否都與1 #if COUNT==1 showMessage("hello,world!\n"); #else say(); #endif return 0; }
文件包含
文件包含指令#include在前面也多次使用過,這里再次強調(diào)一下。首先使用#include“xxx”包含和使用#include <xxx>包含的不同之處就是使用<>包含時,預(yù)處理器會搜索C函數(shù)庫頭文件路徑下的文件,而使用“”包含時首先搜索程序所在目錄,其次搜索系統(tǒng)Path定義目錄,如果還是找不到才會搜索C函數(shù)庫頭文件所在目錄。
另外在使用#include的時候我們需要注意包含文件的時候是不能遞歸包含的,例如a.h文件包含b.h,而b.h就不能再包含a.h了;還有就是重復(fù)包含雖然是允許的但是這會降低編譯性能,不妨看一下下面的例子:
上面有三段代碼,在main.c和person.h中都包含了message.h而main.c自身又包含了person.h,這樣程序在預(yù)處理階段會對包含內(nèi)容進行替換,替換后mian.c中包含了兩個#include “message.h”雖然沒有報錯,但這會影響編譯的性能,正確的做法應(yīng)該是這樣的:
其實就是用宏定義判斷一個宏是否定義了,如果沒有定義則會定義這個宏,這樣以來如果已經(jīng)包含過則這個宏定義肯定已經(jīng)定義過了,即使再包含也不會重新定義了,下面的代碼也就不會包含進去。
相關(guān)文章
舉例講解iOS中延遲加載和上拉刷新/下拉加載的實現(xiàn)
這篇文章主要介紹了舉例講解iOS中延遲加載和上拉刷新/下拉加載的實現(xiàn),語言依然為傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-09-09