Micro definition ---C語言中宏定義使用總結
1、用於定義代碼中不會變化的常量
#define MAX_LEN 1024
2、用於封裝某些常用的代碼塊(不是函數,類似於函數的作用)
#define MAX(x,y) (((x)>(y)) ? (x) : (y))
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
比如這樣的寫法:
#define DRAW_TEXT(f, t, d, use_bg) \
if (d) \
{ \
CvSize _size; \
cvGetTextSize(t, &font, &_size, NULL); \
if (use_bg) \
{ \
cvRectangle(f, cvPoint(0, f->height), \
cvPoint(_size.width + 5, \
f->height - _size.height * 2), \
CV_RGB(255, 0, 0), CV_FILLED, 8, 0); \
} \
cvPutText(f, t, cvPoint(2, f->height - _size.height / 2), \
&font, CV_RGB(255,255,0)); \
d--; \
}
再比如這種:
#define DRAW_RECTS(f, d, rw, ro) \
{ \
cvRectangle(f, POINTS(rw), CV_RGB(255, 0, 0), 1, 8, 0); \
cvRectangle(f, POINTS(ro), CV_RGB(0, 255, 0), 1, 8, 0); \
cvRectangle(d, POINTS(rw), cvScalarAll(255), 1, 8, 0); \
cvRectangle(d, POINTS(ro), cvScalarAll(255), 1, 8, 0); \
}
對於有多個操作,多行代碼最好使用do{...}while(0)包含,防止意外的錯誤。
例如:
有問題的定義:
#define DUMP_WRITE(addr,nr) {memcpy(bufp,addr,nr); bufp += nr;}
應該使用的定義:
#difne DO(a,b) do{a+b;a++;}while(0)
例如:if(addr)
DUMP_WRITE(addr,nr);
else
do_somethong_else();
宏展開以後變成這樣: if(addr)
{memcpy(bufp,addr,nr); bufp += nr;};
else
do_something_else();
gcc 在碰到else前面的“;”時就認爲if語句已經結束,因而後面的else不在if語句中。而採用do{} while(0)的定義,在任何情況下都沒有問題。
有do{...}while(0)時的情況:
if(addr)
do{
memcpy(bufp, addr, nr);
bufp += nr;
}
while(0);
else
do_something_else();
3、用於防止頭文件被重複引用
#ifndef _FILE_HEAD_H_
#define _FILE_HEAD_H_
#endif
還有另外一種方式也可以達到目的(依賴於編譯器,不推薦),有些編譯器不支持
#pragma once
4、消除某些頭文件中已經定義的宏參數
#ifdef MICRO_NAME
#undef MICRO_NAME
#endif
5、用於註釋和打開代碼塊
#if 0
/*your code, want not use*/
#endif
如果需要打開代碼塊,只需將0改成1即可。
若工程中有多處這樣的代碼,需同時打開或同時關閉,可以這樣。
#define DEBUG_FLAG 0
#if DEBUG_FLAG
/*your code*/
#endif
#if DEBUG_FLAG
/*your code*/
#endif
#if DEBUG_FLAG
/*your code*/
#endif
6、使用宏進行跟蹤調試,記錄日誌
ANSI標準說明了五個預定義的宏名。它們是:
__LINE__
__FILE__ /*在MSVC編譯器中__FILE__ 在Debug模式下是帶全路徑的文件名(full path name) Release模式下僅有文件名(file name)*/
/*在vac gcc編譯器中__FILE__ 僅代表文件名(file name)*/
__DATE__
__TIME__
__STDC__
C++中還定義了 __cplusplus 如果編譯器不是標準的,則可能僅支持以上宏名中的幾個,或根本不支持。記住編譯程序也許還提供其它預定義的宏名。
__LINE__ 及 __FILE__ 宏指示,#line指令可以改變它的值,簡單的講,編譯時,它們包含程序的當前行數和文件名。
__DATE__ 宏指令含有形式爲月/日/年的串,表示源文件被翻譯到代碼時的日期。
__TIME__ 宏指令包含程序編譯的時間。時間用字符串表示,其形式爲: 分:秒
__STDC__ 宏指令的意義是編譯時定義的。一般來講,如果__STDC__已經定義,編譯器將僅接受不包含任何非標準擴展的標準C/C++代碼。如果實現是標準的,則宏__STDC__含有十進制常量1。如果它含有任何其它數,則實現是非標準的。
__cplusplus 與標準c++一致的編譯器把它定義爲一個包含至少6爲的數值。與標準c++不一致的編譯器將使用具有5位或更少的數值。 可以定義宏,例如:
當定義了_DEBUG,輸出數據信息和所在文件所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date)
printf(msg);
printf(“%d%d%d”,date,_LINE_,_FILE_) #else
#define DEBUGMSG(msg,date)
#endif
7、關於#pragma
上面有提到過#pragma once可以用於避免頭文件被重複引用。
#pragma comment則更強大:
①windows環境添加lib靜態庫
#pragma comment(lib, "ws2_32.lib")
②windows環境設置控制檯程序連接入口
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) /*設置入口地址, 隱藏控制檯窗口*/
總結:
1.宏名和參數的括號間不能有空格;
2.宏替換隻作替換,不做計算,不做表達式求解;
3. 函數調用在編譯後程序運行時進行,並且分配內存。宏替換在編譯前進行,不分配內存;
4.函數只有一個返回值,利用宏則可以設法得到多個值;
5.宏展開使源程序變長,函數調用不會;
6.宏展開不佔運行時間,只佔編譯時間,函數調用佔運行時間(分配內存、保留現場、值傳遞、返回值);
7.使用條件編譯可以使目標程序變小,運行時間變短;
8.預編譯使問題或算法的解決方案增多,有助於我們選擇合適的解決方案。