日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

c语言宏定义详解

發布時間:2023/12/10 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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

總結

以上是生活随笔為你收集整理的c语言宏定义详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。