C語言宏定義#define的理解與資料梳理
define 函數定義一個常量。爲幫助大家更好地理解這個內容,以下是本站小編搜索整理的關於C語言宏定義#define的理解與資料梳理,供參考借鑑,希望對各位老師有所幫助!想了解更多相關信息請持續關注我們應屆畢業生考試網!
1、利用 define 來定義 數值宏常量
#define 宏定義是個演技非常高超的替身演員,但也會經常耍大牌的,所以我們用它要慎之又慎。它可以出現在代碼的任何地方,從本行宏定義開始,以後的代碼就就都認識這個宏了;也可以把任何東西定義成宏。因爲編譯器會在預編譯的時候用真身替換替身,而在我們的代碼裏面卻又用常常用替身來幫忙。
看例子:
#define PI 3.141592654
在此後的代碼中你儘可以使用PI 來代替3.141592654,而且你最好就這麼做。不然的話,如果我要把PI 的精度再提高一些,你是否願意一個一個的去修改這串數呢?你能保證不漏不出錯?而使用PI 的話,我們卻只需要修改一次(這是十分高效的)。
這種情況還不是最要命的,我們再看一個例子:
#define ERROR_POWEROFF -1
如果你在代碼裏不用ERROR_POWEROFF 這個宏而用-1,尤其在函數返回錯誤代碼的時候(往往一個開發一個系統需要定義很多錯誤代碼)。肯怕上帝都無法知道-1 表示的是什麼意思吧。這個-1,我們一般稱爲“魔鬼數”,上帝遇到它也會發狂的。所以,我奉勸你代碼裏一定不要出現“魔鬼數”。(這裏是從代碼可讀性的角度進行考慮!)
但是我們利用define來定義數值類型的數據,一般只是用來定義 常量 ,如果 要定義一些變量,則可以使用c語言中const這個關鍵字。
我們已經討論了const 這個關鍵字,我們知道const 修飾的數據是有類型的,而define 宏定義的數據沒有類型。爲了安全,我建議你以後在定義一些宏常數的時候用const代替,編譯器會給const 修飾的只讀變量做類型校驗,減少錯誤的可能。
但一定要注意const修飾的不是常量而是readonly 的變量,const 修飾的只讀變量不能用來作爲定義數組的維數,也不能放在case 關鍵字後面。
2、利用 define 來定義 字符串宏常量
除了定義宏常數之外,經常還用來定義字符串,尤其是路徑:
A),#define ENG_PATH_1 E:Englishlisten_to_thislisten_to_this_3
B),#define ENG_PATH_2 “E:Englishlisten_to_thislisten_to_this_3”
噢,到底哪一個正確呢?如果路徑太長,一行寫下來比較彆扭怎麼辦?用反斜槓接續符 ” 啊:
C), #define ENG_PATH_3 E:Englishlisten_to_thislisten_to_this_3
還沒發現問題?這裏用了4 個反斜槓,到底哪個是接續符?回去看看接續符反斜槓。
反斜槓作爲接續符時,在本行其後面不能再有任何字符,空格都不行。所以,只有最後一個反斜槓纔是接續符。至於A)和B),那要看你怎麼用了,既然define 宏只是簡單的替換,那給ENG_PATH_1 加上雙引號不就成了:“ENG_PATH_1”。
但是請注意:有的系統裏規定路徑的要用雙反斜槓“”,比如(這是正確的版本):
#define ENG_PATH_4 E:Englishlisten_to_thislisten_to_this_3
3、用 define 宏定義 註釋符號
上面對define 的使用都很簡單,再看看下面的例子:
#define BSC //
#define BMC /*
#define EMC */
D),BSC my single-line comment
E),BMC my multi-line comment EMC
D)和E)都錯誤,爲什麼呢?因爲註釋先於預處理指令被處理,當這兩行被展開成//…或/*…*/時,註釋已處理完畢,此時再出現//…或/*…*/自然錯誤.(這一條需要對編譯預處理有所理解,才能體會。看來我還得再寫一篇這方面的文章。)
因此,試圖用宏開始或結束一段註釋是不行的。
4、用define 宏定義表達式
這些都好理解,下面來點有“技術含量”的,定義一年有多少秒:
#define SEC_A_YEAR 60*60*24*365
這個定義沒錯吧?很遺憾,很有可能錯了,至少不可靠。你有沒有考慮在16 位系統下把這樣一個數賦給整型變量的時候可能會發生溢出?一年有多少秒也不可能是負數吧。
改一下:
#define SEC_A_YEAR (60*60*24*365)UL
又出現一個問題,這裏的括號到底需不需要呢?繼續看一個例子,定義一個宏函數,求x 的平方:
#define SQR (x) x * x
對不對?試試:假設x 的值爲10,SQR (x)被替換後變成10*10。沒有問題。
再試試:假設x 的值是個表達式10+1,SQR (x)被替換後變成10+1*10+1。問題來了,這並不是我想要得到的。怎麼辦?括號括起來不就完了?
#define SQR (x) ((x)*(x))
最外層的括號最好也別省了,看例子,求兩個數的和:
#define SUM (x) (x)+(x)
如果x 的值是個表達式5*3,而代碼又寫成這樣:SUM (x)* SUM (x)。替換後變成:(5*3)+(5*3)*(5*3)+(5*3)。又錯了!所以最外層的括號最好也別省了。我說過define 是個演技高超的替身演員,但也經常耍大牌。要搞定它其實很簡單,別吝嗇括號就行了。
注意這一點:宏函數被調用時是以實參代換形參。而不是“值傳送”。
5、宏定義中的空格
另外還有一個問題需要引起注意,看下面例子:
#define SUM (x) (x)+(x)
這還是定義的宏函數SUM(x)嗎?顯然不是。編譯器認爲這是定義了一個宏:SUM,其代表的是(x) (x)+(x)。
爲什麼會這樣呢?其關鍵問題還是在於SUM 後面的'這個空格。所以在定義宏的時候一定要注意什麼時候該用空格,什麼時候不該用空格。這個空格僅僅在定義的時候有效,在使用這個宏函數的時候,空格會被編譯器忽略掉。也就是說,上一節定義好的宏函數SUM(x)在使用的時候在SUM 和(x)之間留有空格是沒問題的。比如:SUM(3)和SUM (3)的意思是一樣的。
6、#undef
#undef 是用來撤銷宏定義的,用法如下:
#define PI 3.141592654
…
// code
#undef PI
//下面的代碼就不能用PI 了,它已經被撤銷了宏定義。
寫好C語言,漂亮的宏定義很重要,使用宏定義可以防止出錯,提高可移植性,可讀性,方便性 等等。下面列舉一些成熟軟件中常用得宏定義:
1、防止一個頭文件被重複包含
#ifndef COMDEF_H
#define COMDEF_H
//頭文件內容
#endif
2、重新定義一些類型,防止由於各種平臺和編譯器的不同,而產生的類型字節數差異,方便移植。這裏已經不是#define的範疇了。
typedef unsigned char boolean; /* Boolean value type. */
typedef unsigned long int uint32; /* Unsigned 32 bit value */
typedef unsigned short uint16; /* Unsigned 16 bit value */
typedef unsigned char uint8; /* Unsigned 8 bit value */
typedef signed long int int32; /* Signed 32 bit value */
typedef signed short int16; /* Signed 16 bit value */
typedef signed char int8; /* Signed 8 bit value */
//下面的不建議使用
typedef unsigned char byte; /* Unsigned 8 bit value type. */
typedef unsigned short word; /* Unsinged 16 bit value type. */
typedef unsigned long dword; /* Unsigned 32 bit value type. */
typedef unsigned char uint1; /* Unsigned 8 bit value type. */
typedef unsigned short uint2; /* Unsigned 16 bit value type. */
typedef unsigned long uint4; /* Unsigned 32 bit value type. */
typedef signed char int1; /* Signed 8 bit value type. */
typedef signed short int2; /* Signed 16 bit value type. */
typedef long int int4; /* Signed 32 bit value type. */
typedef signed long sint31; /* Signed 32 bit value */
typedef signed short sint15; /* Signed 16 bit value */
typedef signed char sint7; /* Signed 8 bit value */
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 )
/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */
6、得到一個結構體中field所佔用的字節數
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )
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 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、使用一些宏跟蹤調試
A N S I標準說明了五個預定義的宏名。它們是:
_ LINE _
_ FILE _
_ DATE _
_ TIME _
_ STDC _
可以定義宏,例如:
當定義了_DEBUG,輸出數據信息和所在文件所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif
20、宏定義防止使用是錯誤
用小括號包含。
例如:
#define ADD(a,b) (a+b)
用do{}while(0)語句包含多語句防止錯誤
例如:
#define DO(a,b) a+b;
a++;
應用時:
if(….)
DO(a,b); //產生錯誤
else
解決方法: 代碼就只會執行一次。和直接加花括號有什麼區別呢。哦對,不能隨便在程序中,任意加{},組成代碼塊的。
#define DO(a,b) do{a+b;
a++;}while(0)
相關文章
-
英語作文:The Importance of Self-confidence
Confidence, in a broad sense, comprises self-trust,self-esteem, courage and definition,though somewhat vague and unsubstantial, can be appreciated through experience because iff our lifetime, we are -
英語作文The Importance of Self-confidence
Confidence, in a broad sense, comprises self-trust,self-esteem, courage and definition,though somewhat vague and unsubstantial, can be appreciated through experience because iff our lifetime, we are -
The place of Science and Technology in Modern Life英語作文
human life can not continue without science and technology. for many years, human society has developed with the advance of science and technology while the development of science and technology has i -
I Find My Confidence國中英語作文
I used to be a humble girl, the thing is that I am too humble, I always think that my ability is not good enough, but in fact, I am just not confident. One day, when I went back home after school, my -
Food and place of interest in Beijing國中英語作文
工作總結是爲了我們的工作能夠做得更好,我們的能力有所提高而要求撰寫的,這個工作總結要怎麼去寫呢?《財務人員個人培訓總結三篇》是小編爲大家準備的,希望對大家有幫助。財務人員個人培訓總結培訓雖短,但給我的學習軌跡 -
Win10系統提示Officebackgroundtaskhandler.exe彈窗問題的解決方
win10系統經常彈出名稱爲“”的.彈窗怎麼辦?如何解決?針對這一問題,本文就爲大家圖文介紹Win10系統彈窗問題的解決方法,有興趣的朋友們就來了解下吧!前陣子有不少朋友反映,自己 Windows 10 屏幕總是會彈出一個神祕窗口,眼疾 -
國小英語閱讀理解:WE GIVE AND WE RECEIVE
導語:有付出纔有收穫,所以同學們在日常時多付出精力去學習,才能在考試中取得好成績,下面是本站小編收集的關於收穫與獲得的英語閱讀理解,有興趣的可以看看。 WE GIVE AND WE RECEIVEThis moing, as I saw a beautiful -
Self-confidence英語作文
Self-confidenceThere are many factors that can contribute to a person’s success in life. Whether he is at school or at work, a person is more likely to succeed if he is hard-working, honest, intellig -
Different People Like Different Movies國中英語作文
Different people like different movies. Mary likes comedies, she thinks they are funny. She likes documentaries too, because she thinks documentaries are exciting . She doesn’t like thrillers. She th -
英語閱讀:Life is inevitable consequence of physics
A few years back, a remarkable new hypothesis made its way into the scientific zeitgeist — namely, that life is an inevitable consequence of physics. The author of this concept, an associate pro