c語言巨集定義的使用方法

2021-10-07 19:48:17 字數 3691 閱讀 6236

在工程規模較小,不是很複雜,與硬體結合緊密,要求移植性的時候,可採用巨集定義簡化程式設計,增強程式可讀性。

當巨集作為常量使用時,c程式設計師習慣在名字中只使用大寫字母。但是並沒有如何將用於其他目的的巨集大寫的統一做法。由於巨集(特別是帶引數的巨集)可能是程式中錯誤的**,所以一些程式設計師更喜歡使用大寫字母來引起注意。

簡單巨集定義

無參巨集的巨集名後不帶引數,其定義的一般形式為:

#define 識別符號 字串

// 不帶引數的巨集定義#define max 10

注意:不要在巨集定義中放置任何額外的符號,比如「=」或者尾部加「;」

使用#define來為常量命名一些優點:

程式會更易讀。乙個認真選擇的名字可以幫助讀者理解常量的意義;

程式會更易於修改。我們僅需要改變乙個巨集定義,就可以改變整個程式**現的所有該常量的值;

可以幫助避免前後不一致或鍵盤輸入錯誤;

控制條件編譯;

可以對c語法做小的修改;

帶引數的巨集

帶引數的仍要遵循上述規則,區別只是巨集名後面緊跟的圓括號中放置了引數,就像真正的函式那樣。

#define 《巨集名》(《引數列表》) 《巨集體》

注意引數列表中的引數必須是有效的c識別符號,同時以,分隔

算符優先順序問題:

#define count(m) m*mint x=5;print(count(x+1));print(count(++x));//結果輸出:11 和42 而不是函式的輸出36

注意:預編譯器只是進行簡單的文字替換,count(x+1)被替換成count(x+1 x+1),5+15+1=11,而不是36

cunt(++x)被替換成++x*++x即為6 7=42,而不是想要的66=36,連續前置自加加兩次

解決辦法:

用括號將整個替換文字及每個引數用括號括起來print(count((x+1));

即便是加上括號也不能解決第二種情況,所以解決辦法是盡量不使用++,-等符號;分號吞噬問題:

#define foo(x) bar(x); baz(x)

假設這樣呼叫:

if (!feral) foo(wolf);

將被巨集擴充套件為:

if (!feral) bar(wolf);baz(wolf);

baz(wolf);,不在判斷條件中,顯而易見,這是錯誤。如果用大括號將其包起來依然會有問題,例如

#define foo(x) if (!feral) foo(wolf);else bin(wolf);

判斷語言被擴充套件成:

if (!feral) 》++;++《else bin(wolf);

else將不會被執行

解決方法:通過==dowhile(0)

#define foo(x) dowhile(0)if (!feral) foo(wolf);else bin(wolf);

被擴充套件成:

#define foo(x) dowhile(0)if (!feral) dowhile(0);else bin(wolf);

注意:使用dowhile(0)構造後的巨集定義不會受到大括號、分號等的影響,總是會按你期望的方式呼叫執行。

#運算子

#的作用就是將#後邊的巨集引數進行字串的操作,也就是將#後邊的引數兩邊加上一對雙引號使其成為字串。例如a是乙個巨集的形參,則替換文字中的#a被系統轉化為「a」,這個轉換過程即為字串化。

#define test(param) #paramchar *pstr=test(123);printf(「psrt=%s\n」,pstr);//輸出結果為字元 」123「

##運算子

##運算子也可以用在替換文字中,它的作用起到粘合的作用,即將兩個巨集引數連線為乙個數

#define test(param1,param2) (param1##param2)int num =test(13,59);printf(「num=%d\n」,num);//輸出結果為:num=1359

va_args

作用主要是為了方便管理軟體中的列印資訊。在寫**或debug時通常需要將一些重要引數列印出來,但在軟體發行的時候不希望有這些列印,這時就用到可變引數巨集了。

2 一些建議雖然巨集定義很靈活,並且通過彼此結合可以產生許多變形用法,但是c++/c程式設計師不要定義很複雜的巨集,巨集定義應該簡單而清晰。

巨集名採用大寫字元組成的單詞或其縮寫序列,並在各單詞之間使用「_」分隔。

如果需要公布某個巨集,那麼該巨集定義應當放置在標頭檔案中,否則放置在實現檔案(.cpp)的頂部。

不要使用巨集來定義新型別名,應該使用typedef,否則容易造成錯誤。

給巨集新增注釋時請使用塊注釋(/* */),而不要使用行注釋。因為有些編譯器可能會把巨集後面的行注釋理解為巨集體的一部分。

盡量使用const取代巨集來定義符號常量。

對於較長的使用頻率較高的重複**片段,建議使用函式或模板而不要使用帶引數的巨集定義;而對於較短的重複**片段,可以使用帶引數的巨集定義,這不僅是出於型別安全的考慮,而且也是優化與折衷的體現。

盡量避免在區域性範圍內(如函式內、型別定義內等)定義巨集,除非它只在該區域性範圍內使用,否則會損害程式的清晰性。

3 巨集的常見用法防止乙個標頭檔案被重複包含

#ifndef comdef_h#define comdef_h//標頭檔案內容#endif

得到指定位址上的乙個位元組或字

#define mem_b(x) (*((byte )(x)))#define mem_w(x) (((word *)(x)))

求最大值和最小值

#define max(x,y) (((x)》(y)) ? (x) : (y))#define min(x,y) (((x) 《 (y)) ? (x) : (y))

得到乙個field在結構體(struct)中的偏移量

#define fpos(type,field) ((dword)&((type *)0)-》field)

得到乙個結構體中field所占用的位元組數

#define fsiz(type,field) sizeof(((type *)0)-》field)

按照lsb格式把兩個位元組轉化為乙個word

#define flipw(ray) ((((word)(ray)[0]) * 256) + (ray)[1])

得到乙個字的高位和低位位元組

#define word_lo(***) ((byte) ((word)(***) & 255))#define word_hi(***) ((byte) ((word)(***) 》 8))

將乙個字母轉換為大寫

#define upcase(c) (((c)》=『a』 && (c) 《= 『z』) ? ((c) – 0×20) : (c))

判斷字元是不是10進製的數字

#define decchk(c) ((c)》=『0』 && (c)《=『9』)

判斷字元是不是16進製制的數字

#define hexchk(c) (((c) 》= 『0』 && (c)《=『9』) ((c)》=『a』 && (c)《= 『f』) \((c)》=『a』 && (c)《=『f』))

防止溢位的乙個方法

#define inc_sat(val) (val=((val)+1》(val)) ? (val)+1 : (val))

返回陣列元素的個數

#define arr_size(a) (sizeof((a))/sizeof((a[0])))

c語言入門,看這裡c語言程式設計基礎

c語言 陣列和字串

c語言 指標專題一

c語言可控制led燈

C語言 define巨集的定義與使用方法

一.巨集的概念與定義方法 1.被定義為 巨集 的標示符稱為 巨集名 在編譯預處理時,對程式中所有出現的 巨集名 都用巨集定義中德字串去替換,這稱為 巨集替換 或者 巨集展開 2.巨集定義是由源程式中德巨集定義命令完成的.巨集替換是由預處理程式自動完成的 在c語言中,巨集 分為有引數和無引數兩中.二....

C語言巨集定義使用方法和注意事項

一 總結 1 預處理器直接對巨集進行文字替換 2 巨集使用時的引數不會進行求值和運算 3 預處理器不會對巨集定義進行語法檢查,巨集定義時出現的語法錯誤只能被編譯器檢測 4 巨集定義的效率高於函式呼叫 巨集不占用記憶體,函式占用記憶體 5 巨集的使用會帶來一定的 6 define定義的巨集可以出現在程...

C C 巨集定義中 和 的使用方法

單井號 在巨集定義中,不展開引數,直接替換,作用是把傳遞過來的引數當成字串進行替換。雙井號 又稱連線符,它的作用是將引數和前面或後面的子串連線起來,成為乙個新的子串。using namespace std define age param printf s的年齡是 d n param,param a...