在寫程序時經常會碰到這樣一個問題,我們需要重復寫很多相同的代碼,並且這些代碼結構相同。總是想自己把這段代碼封裝一下然后直接進行調用,但是如果這段代碼邏輯並不復雜,並且代碼量也不大,不適合進行封裝,那么我們就會想到c++中的關鍵字define。其實明智的你,遇到上面的這些情況估計還會想到另一個東西----template,后面我們也會說一下兩者的卻別。今天自己看了一下c++ define的相關知識,做個記錄。
1.什么是define: 宏定義,簡單的理解就是替換,其實這也是本質。如果熟悉g++編譯過程的話,會了解到一個概念叫做預處理,就是在編譯之前做個處理。這個過程並不像編譯那么復雜,就是簡單的遞歸替換和刪除。替換的就是宏定義和include文件,刪除注釋。注意這里我們談到一個概念,遞歸替換,這個其實是很常見的,比如你的程序中include一個.h文件,但是這個.h文件中還引入了另一個.h文件,那么這個時候就需要進行遞歸替換。這個我們自己查看一下究竟預處理都干了些什么?(為了減少預處理之后的代碼我們不引入其他文件)
這樣我們就更好的理解define的作用和預處理的作用了。
2.define的使用方法:
-
- 簡單使用:define identifier replacement-list(optional) 這是最基本的使用方法,就像上面我們的例子一下,在預處理的時候將identifier替換成replacement-list(optional)。比如:在開發程序的時候會定義很多錯誤碼,比如使用22表示圖片上傳成功,如果我們這樣進行判斷assert(result==22)。看似是沒什么問題,那么要是你看了誰的代碼是這樣寫的,你會怎么想?誰寫的,這22是什么意思? 這時候就需要我們給22起一個別名,例如: #define Success = 22
- 帶參形式:除了上面的使用方法我們還可以給定參數來進行宏定義,比如:
#include<iostream> #include<string.h>
//定義了一個宏,將A,B進行連接 #define Append(A,B) A+B; using namespace std; int main(int argc, char *argv[]) { string test1 = "1"; string test2 = "2";
//進行宏定義的調用 cout<<Append(test1,test2); return 0; }從這個例子我們可以看出宏定義的好處之一:可以在一定程度上忽略宏定義中參數的類型,這一點是不是和template很相似,我們使用template來重寫一下上面的這段代碼:
#include<iostream> #include<string.h> using namespace std;
//定義模板方法 template<class T> T append(T a,T b){ return a+b; } int main(int argc, char *argv[]) { string A = "1"; string B = "2"; //使用模板方法
cout<<append(A,B); return 0; }這里我們是不是會覺得在這種情況下面宏定義與template是一致的?其實並不是,我們考慮一下下面的這種情況,假設存在這樣一個宏定義#define add(a,b) a+b,並且在代碼中調用過程是這樣的a*add(a,b)*b;大家可以想想結果是多少?答案是5,而不是我們預期的6,原因很簡單,這只是簡單的替換,經過預處理之后的結果是a*a+b*b。但是template運算的結果就是6,這就是差別。所以在使用的時候還是應該考慮是選擇template還是define。
-
define中代碼段的表示: 上面我們說到的宏定義都是簡單的一條語句,如果我們需要定義一個稍微復雜一點的語句呢?比如:我們習慣,或者說是個人習慣,喜歡把一些判斷語句進行宏定義,比如我們在進行一個功能錯誤碼的校驗的時候通常希望能夠將代碼和log日志分開,使得代碼顯得不那么凌亂,那么我們將會定義一個稍微復雜一點的宏定義。
#include<iostream> #include<string.h>
//宏定義一個MaxName #define MaxName 10
//宏定義 定義了一個判斷條件用於識別圖片上傳之后的返回碼 並輸出日志條件 #define AssertReturnValue(name,result)do{\ if(result==0)\ cout<<"圖片"<<name<<"上傳成功";\ }while(0) using namespace std; class Picture { public: Picture (const char *path,const char *file){ strcpy(this->path,path); strcpy(this->file,file); } ~Picture (){ } private: char file[MaxName]; char path[MaxName]; }; int uploadPicture(const Picture picture) { cout<<"成功"; return 0; } int main(int argc, char *argv[]) { Picture picture("100","100"); int result = uploadPicture(picture);
//調用結果判斷宏定義 AssertReturnValue("100",result); return 0; }這里我們應該注意一下,代碼段的宏定義的寫法。
- 條件宏定義ifdef:可以在編譯的時候通過#define設置編譯環境,語法結構:
//不同的運行環境,不同的頭文件 #ifdef OS_Win #include <windows.h> #endif #ifdef OS_Linux #include <linux.h> #endif
下面我們將c++ 常用的宏定義羅列一下:
-
#空指令,無任何效果 #include包含一個源代碼文件 #define定義宏 #undef取消已定義的宏 #if如果給定條件為真,則編譯下面代碼 #ifdef如果宏已經定義,則編譯下面代碼 #ifndef如果宏沒有定義,則編譯下面代碼 #elif如果前面的#if給定條件不為真,當前條件為真,則編譯下面代碼 #endif結束一個#if……#else條件編譯塊 #error停止編譯並顯示錯誤信息
參考http://www.cnblogs.com/zi-xing/p/4550246.html