篇一 : define用法集錦
Definition:
The #define Directive
You can use the #define directive to give a meaningful name to a constant in your program. The two forms of the syntax are:
Syntax
#define identifier token-stringopt
#define identifier[( identifieropt, ... , identifieropt )] token-stringopt
Usage:
1. 簡單的define定義
#define MAXTIME 1000
一個簡單的MAXTIME就定義好了,它代表1000,如果在程式裡面寫
if(i<MAXTIME){.........}
編譯器在處理這個代碼之前會對MAXTIME進行處理替換為1000。[www.t262.com)
這樣的定義看起來類似于普通的常量定義CONST,但也有着不同,因為define的定義更像是簡單的文本替換,而不是作為一個量來使用,這個問題在下面反映的尤為突出。
2.define的“函數定義”
define可以像函數那樣接受一些參數,如下
#define max(x,y) ((x)>(y)?(x):(y));
這個定義就将傳回兩個數中較大的那個,看到了嗎?因為這個“函數”沒有類型檢查,就好像一個函數模闆似的,當然,它絕對沒有模闆那麼安全就是了。可以作為一個簡單的模闆來使用而已。
但是這樣做的話存在隐患,例子如下:
#define Add(a,b) a+b;
在一般使用的時候是沒有問題的,但是如果遇到如:c * Add(a,b) * d的時候就會出現問題,代數式的本意是a+b然後去和c,d相乘,但是因為使用了define(它隻是一個簡單的替換),是以式子實際上變成了
c*a + b*d
另外舉一個例子:
#define pin (int*);
pin a,b;
本意是a和b都是int型指針,但是實際上變成int* a,b;
a是int型指針,而b是int型變量。
這是應該使用typedef來代替define,這樣a和b就都是int型指針了。
是以我們在定義的時候,養成一個良好的習慣,建議所有的層次都要加括号。
3.宏的單行定義(少見用法)
#define A(x) T_##x
#define B(x) #@x
#define C(x) #x
我們假設:x=1,則有:
A(1)------〉T_1
define define用法集錦
B(1)------〉'1'
C(1)------〉"1"
(這裡參考了 hustli的文章)
3.define的多行定義
define可以替代多行的代碼,例如MFC中的宏定義(非常的經典,雖然讓人看了惡心)但是如果隻有一個語句,完全沒有必要用do while
#define MACRO(arg1, arg2) do { \
\
stmt1; \
stmt2; \
\
} while(0)
關鍵是要在每一個換行的時候加上一個"\"
如果你想在宏中包含多個語句,可能會這樣寫:
#define do_something() \
do_a(); \
do_b();
這樣你就可以用 do_somethin() 來執行一系列操作.
但這樣會有個問題: 如果你下面這樣用這個宏地話:
if (...)
do_something();
當宏被展開後就變成:
if (...)
do_a();
do_b();
發現問題沒? 原代碼的目的是想在 if 為真的時候執行 do_a() 和 do_b(), 但現在呢? 隻有 do_a() 在條件語句中, do_b() 任何時候都會執行的.
這時你可能會将那個宏改進一下:
#define do_something() { \
do_a(); \
do_b(); \
}
看樣子行了, 是嗎? 如果我這個宏是這個樣子的呢:
#define do_something() { \
define define用法集錦
if (a) \
do_a(); \
else \
do_b();
}
這麼使用:
if (...)
do_something();
else {
...
}
宏展開後:
if (...)
{
if (a)
do_a();
else
do_b();
}; else {
}
注意到第二個 else 前邊那個分号了嗎?
是以有人想到了用 do { } while (0) 來解決這個問題, do {} while 語句是需要分号來結束的, 另外, 現代編譯器的優化子產品能夠足夠聰明地注意到這個循環隻會執行一次而将其優化掉.
綜上所述, do { } while(0) 這個技術就是為了類似的宏可以在任何時候使用.
注: 如果你看過 linux 核心源代碼, 這個技巧非常常見
4.在大規模的開發過程中,特别是跨平台和系統的軟體裡,define最重要的功能是條件編譯。(www.t262.com) 就是:
#ifdef WINDOWS
......
......
#endif
#ifdef LINUX
......
......
define define用法集錦
#endif
可以在編譯的時候通過#define設定編譯環境
5.如何定義宏、取消宏
//定義宏
#define [MacroName] [MacroValue]
//取消宏
#undef [MacroName]
//普通宏
#define PI (3.1415926)
帶參數的宏
#define max(a,b) (((a)>(b)? (a),(b)))
關鍵是十分容易産生錯誤,包括機器和人了解上的差異等等。(www.t262.com]
6.條件編譯
#ifdef XXX?(#else) ? #endif
例如
#ifdef DV22_AUX_INPUT
#define AUX_MODE 3
#else
#define AUY_MODE 3
#endif
#ifndef XXX ? (#else) ? #endif
7.頭檔案(.h)可以被頭檔案或C檔案包含;
重複包含(重複定義)
由于頭檔案包含可以嵌套,那麼C檔案就有可能包含多次同一個頭檔案,就可能出現重複定義的問題的。 通過條件編譯開關來避免重複包含(重複定義)
例如
#ifndef __headerfileXXX__
#define __headerfileXXX__
?
//檔案内容
?
#endif
define define用法集錦
Instances:
1、防止一個頭檔案被重複包含
#ifndef COMDEF_H
#define COMDEF_H
//頭檔案内容
#endif
2、重新定義一些類型,防止由于各種平台和編譯器的不同,而産生的類型位元組數差異,友善移植。(www.t262.com) typedef unsigned char boolean;
typedef unsigned long int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
typedef signed long int int32;
typedef signed short int16;
typedef signed char int8;
//下面的不建議使用
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
typedef unsigned char uint1;
typedef unsigned short uint2;
typedef unsigned long uint4;
typedef signed char int1;
typedef signed short int2;
typedef long int int4;
typedef signed long sint31;
typedef signed short sint15;
typedef signed char sint7;
3、得到指定位址上的一個位元組或字
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
4、求最大值和最小值
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
5、得到一個field在結構體(struct)中的偏移量
#define FPOS( type, field ) \
( (dword) &(( type *) 0)-> field )
6、得到一個結構體中field所占用的位元組數
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )
define define用法集錦
7、按照LSB格式把兩個位元組轉化為一個Word
#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )
8、按照LSB格式把一個Word轉化為兩個位元組
#define FLOPW( ray, val ) \
(ray)[0] = ((val) / 256); \
(ray)[1] = ((val) & 0xFF)
9、得到一個變量的位址(word寬度)
#define B_PTR( var ) ( (byte *) (void *) &(var) )
#define W_PTR( var ) ( (word *) (void *) &(var) )
10、得到一個字的高位和低位位元組
#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))
#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))
11、傳回一個比X大的最接近的8的倍數
#define RND8( x ) ((((x) + 7) / 8 ) * 8 )
12、将一個字母轉換為大寫
#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
13、判斷字元是不是10進值的數字
#define DECCHK( c ) ((c) >= '0' && (c) <= '9')
14、判斷字元是不是16進值的數字
#define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\
((c) >= 'A' && (c) <= 'F') ||\
((c) >= 'a' && (c) <= 'f') )
15、防止溢出的一個方法
#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
16、傳回數組元素的個數
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
17、傳回一個無符号數n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)
#define MOD_BY_POWER_OF_TWO( val, mod_by ) \
( (dword)(val) & (dword)((mod_by)-1) )
18、對于IO空間映射在存儲空間的結構,輸入輸出處理
#define inp(port) (*((volatile byte *) (port)))
#define inpw(port) (*((volatile word *) (port)))
#define inpdw(port) (*((volatile dword *)(port)))
define define用法集錦
#define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
19、使用一些宏跟蹤調試
ANSI标準說明了五個預定義的宏名。[www.t262.com)它們是:
__LINE__
__FILE__
__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
20、宏定義防止錯誤使用小括号包含。
例如:
有問題的定義:#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
define define用法集錦
do_something_else();
gcc在碰到else前面的“;”時就認為if語句已經結束,因而後面的else不在if語句中。[www.t262.com]而采用do{} while(0)的定義,在任何情況下都沒有問題。而改為 #difne DO(a,b) do{a+b;a++;}while(0) 的定義則在任何情況下都不會出錯
21. define中的特殊辨別符
#define Conn(x,y) x##y
#define ToChar(x) #@x
#define ToString(x) #x
int a=Conn(12,34);
char b=ToChar(a);
char c[]=ToString(a);
結果是 a=1234,c='a',c='1234';
可以看出 ## 是簡單的連接配接符,#@用來給參數加單引号,#用來給參數加雙引号即轉成字元串
篇二 : define:define-參數,define-作用
define,無參宏定義的一般形式為:#define 辨別符 字元串。define() 函數定義一個常量。正如C語言中所講,函數的使用可以使程式更加子產品化,便于組織,而且可重複利用,但在發生函數調用時,需要保留調用函數的現場,以便子函數執行結束後能傳回繼續執行,同樣在子函數執行完後要恢複調用函數的現場,這都需要一定的時間,如果子函數執行的操作比較多,這種轉換時間開銷可以忽略,但如果子函數完成的功能比較少,甚至于隻完成一點操作,如一個乘法語句的操作,則這部分轉換開銷就相對較大了,但使用帶參數的宏定義就不會出現這個問 題,因為它是在預處理階段即進行了宏展開,在執行時不需要轉換,即在當地執行。
define_define -參數
#define GPEBLT_FUNCNAME(basename) (SCODE (GPE::*)(struct GPEBltParms *))&GPE::##basename
在#define中,标準隻定義了#和##2種操作。#用來把參數轉換成字元串,##則用來連接配接前後2個參數,把它們變成1個字元串。
輸出為:token 9 = 10
詳見百科typedef(相似)。
define_define -作用
被定義為“宏”的辨別符稱為“宏名”。在編譯預處理時,對程式中所有出現的“宏名”,都用宏定義中的字元串去代換,這稱為“宏代換”或“宏展開”。宏定義是由源程式中的宏定義指令完成的。宏代換是由預處理程式自動完成的。
宏定義的作用範圍僅限于目前檔案,即file1.c中定義 #define PI 3.14,在file2.c中該宏定義不起作用;通過将#define PI 3.14定義在common.h中,file1.c和file2.c分别#include "common.h"的方式,該宏定義在file1.c和file2.c中都起作用。
在C或C++語言中,“宏”分為有參數和無參數2種。
define_define -宏定義優點
(1) 友善程式的修改
使用簡單宏定義可用宏代替1個在程式中經常使用的常量,這樣在将該常量改變時,不用對整個程式進行修改,隻修改宏定義的字元串就可以,而且當常量比較長時, 我們可以用較短的有意義的辨別符來寫程式,這樣更友善一些。我們所說的常量改變不是在程式運作期間改變,而是在程式設計期間的修改,舉1個大家比較熟悉的例 子,圓周率π是在數學上常用的1個值,有時我們會用3.14來表示,有時也會用3.1415926等,這要看計算所需要的精度,如果我們編制的1個程式中 要多次使用它,那麼需要确定1個數值,在本次運作中不改變,但也許後來發現程式所表現的精度有變化,需要改變它的值, 這就需要修改程式中所有的相關數值,這會給我們帶來一定的不便,但如果使用宏定義,使用1個辨別符來代替,則在修改時隻修改宏定義就可以,還可以減少輸入 3.1415926這樣長的數值多次的情況,我們可以如此定義 #define pi 3.1415926,既減少了輸入又便于修改,何樂而不為呢?
(2) 提高程式的運作效率
使用帶參數的宏定義可完成函數調用的功能,又能減少系統開銷,提高運作效率。正如C語言中所講,函數的使用可以使程式更加子產品化,便于組織,而且可重複利用,但在發生函數調用時,需要保留調用函數的現場,以便子函數執行結束後能傳回繼續執行,同樣在子函數執行完後要恢複調用函數的現場,這都需要一定的時間,如果子函數執行的操作比較多,這種轉換時間開銷可以忽略,但如果子函數完成的功能比較少,甚至于隻完成一點操作,如1個乘法語句的操作,則這部分轉換開銷就相對較大了,但使用帶參數的宏定義就不會(www.t262.com]出現這個問 題,因為它是在預處理階段即進行了宏展開,在執行時不需要轉換,即在當地執行。宏定義可完成簡單的操作,但複雜的操作還是要由函數調用來完成,而且宏定義所占用的目标代碼空間相對較大。是以在使用時要依據具體情況來決定是否使用宏定義。
define_define -無參宏定義
無參宏定義的一般形式為:#define 辨別符 字元串
其中的“#”表示這是一條預處理指令。凡是以“#”開頭的均為預處理指令。“define”為宏定義指令。“辨別符”為所定義的宏名。“字元串”可以是常數、表達式、格式串等。
例如:#define M (a+b)它的作用是指定辨別符M來代替表達式(a+b)。在編寫源程式時,所有的(a+b)都可由M代替,而對源程式作編譯時,将先由預處理程式進行宏代換,即用(a+b)表達式去置換所有的宏名M,然後再進行編譯。
程式1:
上例程式中首先進行宏定義,定義M來替代表達式(a+b),在 s= M * M 中作了宏調用。在預處理時經宏展開後該語句變為: S=(a+b)*(a+b) 但要注意的是,在宏定義中表達式(a+b)兩邊的括号不能少。否則會發生錯誤。 如當作以下定義後:#define M (a)+(b) 在宏展開時将得到下述語句:S= (a)+(b)*(a)+(b)
對于宏定義還要說明以下幾點:
1.宏定義是用宏名來表示1個字元串,在宏展開時又以該字元串取代宏名,這隻是1種簡單的代換,字元串中可以含任何字元,可以是常數,也可以是表達式,預處理程式對它不作任何檢查。如有錯誤,隻能在編譯已被宏展開後的源程式時發現。
2.宏定義不是說明或語句,在行末不必加分号,如加上分号則連分号也一起置換。
3.宏定義其作用域為宏定義指令起到源程式結束。如要終止其作用域可使用#undef指令。 (有關#undef 請查閱其他資料)
define_define -帶參宏定義
c語言允許宏帶有參數。在宏定義中的參數稱為形式參數,在宏調用中的參數稱為實際參數。對帶參數的宏,在調用中,不僅要宏展開,而且要用實參去代換形參。
帶參宏定義的一般形式為: #define 宏名(形參表) 字元串
在字元串中含有各個形參。 帶參宏調用的一般形式為: 宏名(形參表)
例如:
在宏調用時,用實參5去代替形參y,經預處理宏展開後的語句為: k=5*5+3*5
程式2:
上例程式的第一行進行帶參宏定義,用宏名MAX表示條件表達式 (a>b)?a:b ,形參a,b均出現在條件表達式中。程式中 max=MAX(x,y) 為宏調用,實參x,y,将代換形參a,b。宏展開後該語句為: max=(x>y)?x:y; 用于計算x,y中的大數。
#define 條件編譯
頭檔案(.h)可以被頭檔案或C檔案包含;重複包含(重複定義)由于頭檔案包含可以嵌套,那麼C檔案就有可能包含多次同1個頭檔案,就可能出現重複定義的問題的。 通過條件編譯開關來避免重複包含(重複定義)
例如
詳見百科#typedef(相似)
define_define -PHP用法
define() 函數定義1個常量。
常量類似變量,不同之處在于:
在設定以後,常量的值無法更改
常量名不需要開頭的美元符号 ($)
作用域不影響對常量的通路
常量值隻能是字元串或數字
define_define -例子
例子1
定義1個大小寫敏感的常量:
輸出:
Hello world!
例子2
定義1個大小寫不敏感的常量:
輸出:
Hello world!
轉自: