c语言宏定义详解
1,防止一個頭文件被重復包含?
#ifndef?COMDEF_H?
#define?COMDEF_H?
??//頭文件內容?
#endif?
2,重新定義一些類型,防止由于各種平臺和編譯器的不同,而產生的類型字節數 差異,方便移植。?
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?*/?
分析:
#include?
typedef struct person {
?? ?int num;
?? ?int age;
?? ?char name[20];
}person;
#define FPOS(type,field) sizeof(((type *)0)->field)
main()
{
?? ?printf("%d\n",FPOS(person,name));
}
^_^[sunny@localhost ~]52$ ./a.out?
20
#define OFFSETOF(type, field) ((size_t)&(((type *)0)->field))
(type *)0:把0地址當成type類型的指針。
((type *)0)->field:對應域的變量。
&((type *)0)->field:取該變量的地址,其實就等于該域相對于0地址的偏移量。
(size_t)&(((type *)0)->field):將該地址(偏移量)轉化為size_t型數據。
ANSI C標準允許任何值為0的常量被強制轉換成任何一種類型的指針,并且轉換結果是一個NULL指針,因此((s*)0)的結果就是一個類型為s*的NULL指 針。如果利用這個NULL指針來訪問s的成員當然是非法的,但&(((s*)0)->m)的意圖并非想存取s字段內容,而僅僅是計算當結構 體實例的首址為((s*)0)時m字段的地址。聰明的編譯器根本就不生成訪問m的代碼,而僅僅是根據s的內存布局和結構體實例首址在編譯期計算這個(常 量)地址,這樣就完全避免了通過NULL指針訪問內存的問題。
有人這樣表達:
#define OFFSETOF(type, field) ((size_t) \
?????????????? ((char *)&((type *)0)->field - (char *)(type *)0))
我認為效果是一樣的,多增加的那部分就是0地 址,相減后就是偏移量。
為什么要增加size_t呢?
首先size_t的定義是什么呢,在文件 stddef.h中可以找到答案。
typedef unsigned int size_t;????????????????????? /*mine is 32bit machine*/
可見就是將偏移量轉化為無符整型,其實32位 機器的地址就是無符號的32位整數。一般情況下,不進行size_t類型轉化也是沒有問題的(后面的實驗可證)。我認為,只有偏移量足夠大,當大于 0x80000000時才有影響,因為這時候的偏移量最高位是1,機器默認為是負數了。似乎上面宏定義OFFSETOF中更能說明這個問題,因為這個宏定 義是一個差值,最高位是1就肯定是負數了。使用printf("%d", &var);打印一個變量的地址就是個負數。這只是我的看法,網上基本沒有什么人分析為什么添加size_t的強制類型轉化。因為系統對數組長度 的大小是有限制的,所以也不能實驗得到數據。
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標準說明了 五個預定義的宏名。它們是:?
_?L?I?N?E?_?
_?F?I?L?E?_?
_?D?A?T?E?_?
_?T?I?M?E?_?
_?S?T?D?C?_?
如果編譯不是標準的,則可能僅支持以上宏名中的幾個,或根本不支持。記住編譯程序?
也許還提供其它預定義的宏名。?
_?L?I?N?E?_及_?F?I?L?E?_宏 指令在有關#?l?i?n?e的 部分中已討論,這里討論其余的宏名。?
_?D?AT?E?_宏指令含有形式為月/日/年的串,表示源文件被翻譯到代碼時的日期。?
源代碼翻譯到目標代碼的時間作為串包含在_?T?I?M?E?_中。串形式為 時:分:秒。?
如果實現是標準的,則宏_?S?T?D?C?_含有十進制常量1。如果它含有任何其它數,則實現是?
非標準的。?
可以定義宏,例如:?
當定義了_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)語 句包含多語句防止錯誤?
例如:#difne?DO(a,b)?a+b;\?
???????????????????a++;?
應 用時:if(….)?
??????????DO(a,b);?//產 生錯誤?
????????else?
解 決方法:?#difne?DO(a,b)?do{a+b;\?
???????????????????a++;}while(0)?宏 中"#"和"##"的用法?
一、一般用法?
我們使用#把宏參數變為一個字符串,用##把兩個宏參數貼合在一起.?
用法:?
#include<cstdio>?
#include<climits>?
using?namespace?std;?
#define?STR(s)?????#s?
#define?CONS(a,b)??int(a##e##b)?
int?main()?
{?
????printf(STR(vck));???????????//?輸出字符串"vck"?
????printf("%d\n",?CONS(2,3));??//?2e3?輸 出:2000?
????return?0;?
}?
二、 當宏參數是另一個宏的時候?
需要注意的是凡 宏定義里有用''#''或''##''的地 方宏參數是不會再展開.?
1,?非''#''和''##''的情況?
#define?TOW??????(2)?
#define?MUL(a,b)?(a*b)?
printf("%d*%d=%d\n",?TOW,?TOW,?MUL(TOW,TOW));?
這行的宏會被展開為:?
printf("%d*%d=%d\n",?(2),?(2),?((2)*(2)));?
MUL里的參數TOW會被展開為(2).?
2,?當有''#''或''##''的時候?
#define?A??????????(2)?
#define?STR(s)?????#s?
#define?CONS(a,b)??int(a##e##b)?
printf("int?max:?%s\n",??STR(INT_MAX));????//?INT_MAX?#include<climits>?
這行會被展開為:?
printf("int?max:?%s\n",?"INT_MAX");?
printf("%s\n",?CONS(A,?A));???????????????//?compile?error??
這 一行則是:?
printf("%s\n",?int(AeA));?
INT_MAX和A都 不會再被展開,?然而解決這個問題的方法很簡單.?加 多一層中間轉換宏.?
加這層宏的用意是把所 有宏的參數在這層里全部展開,?那么在轉換宏里的那一個宏(_STR)就 能得到正確的宏參數.?
#define?A???????????(2)?
#define?_STR(s)?????#s?
#define?STR(s)??????_STR(s)??????????//?轉 換宏?
#define?_CONS(a,b)??int(a##e##b)?
#define?CONS(a,b)???_CONS(a,b)???????//?轉 換宏?
printf("int?max:?%s\n",?STR(INT_MAX));??????????//?INT_MAX,int型的最大值,為一個變量?#include<climits>?
輸出為:?int?max:?0x7fffffff?
STR(INT_MAX)?-->??_STR(0x7fffffff)?然 后再轉換成字符串;?
printf("%d\n",?CONS(A,?A));?
輸 出為:200?
CONS(A,?A)??-->??_CONS((2),?(2))??-->?int((2)e(2))?
三、''#''和''##''的一些應用特例?
1、合并匿名變量名?
#define??___ANONYMOUS1(type,?var,?line)??type??var##line?
#define??__ANONYMOUS0(type,?line)??___ANONYMOUS1(type,?_anonymous,?line)?
#define??ANONYMOUS(type)??__ANONYMOUS0(type,?__LINE__)?
例:ANONYMOUS(static?int);??即:?static?int?_anonymous70;??70表 示該行行號;?
第一層:ANONYMOUS(static?int);??-->??__ANONYMOUS0(static?int,?__LINE__);?
第二層:????????????????????????-->??___ANONYMOUS1(static?int,?_anonymous,?70);?
第三層:????????????????????????-->??static?int??_anonymous70;?
即每次只能解開當前層的宏,所以__LINE__在第二層才能被解開;?
2、填充結構?
#define??FILL(a)???{a,?#a}?
enum?IDD{OPEN,?CLOSE};?
typedef?struct?MSG{?
??IDD?id;?
??const?char?*?msg;?
}MSG;?
MSG?_msg[]?=?{FILL(OPEN),?FILL(CLOSE)};?
相當 于:?
MSG?_msg[]?=?{{OPEN,?"OPEN"},?
??????????????{CLOSE,?"CLOSE"}};?
3、記錄文件名?
#define??_GET_FILE_NAME(f)???#f?
#define??GET_FILE_NAME(f)????_GET_FILE_NAME(f)?
static?char??FILE_NAME[]?=?GET_FILE_NAME(__FILE__);?
4、 得到一個數值類型所對應的字符串緩沖大小?
#define??_TYPE_BUF_SIZE(type)??sizeof?#type?
#define??TYPE_BUF_SIZE(type)???_TYPE_BUF_SIZE(type)?
char??buf[TYPE_BUF_SIZE(INT_MAX)];?
?????-->??char??buf[_TYPE_BUF_SIZE(0x7fffffff)];?
?????-->??char??buf[sizeof?"0x7fffffff"];?
這里相當于:?
char??buf[11];?
轉載于:https://www.cnblogs.com/guyandianzi/p/8582638.html
總結
- 上一篇: 进度管理
- 下一篇: java linux socket编程_