C语言宏定义技巧介绍
|
|
1,防止一个头文件被重复包含
#ifndefCOMDEF_H #defineCOMDEF_H //头文件内容 #endif 2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。 typedefunsignedcharboolean;/*Booleanvaluetype.*/ typedefunsignedlongintuint32;/*Unsigned32bitvalue*/ typedefunsignedshortuint16;/*Unsigned16bitvalue*/ typedefunsignedcharuint8;/*Unsigned8bitvalue*/ typedefsignedlongintint32;/*Signed32bitvalue*/ typedefsignedshortint16;/*Signed16bitvalue*/ typedefsignedcharint8;/*Signed8bitvalue*/ //下面的不建议使用 typedefunsignedcharbyte;/*Unsigned8bitvaluetype.*/ typedefunsignedshortword;/*Unsinged16bitvaluetype.*/ typedefunsignedlongdword;/*Unsigned32bitvaluetype.*/ typedefunsignedcharuint1;/*Unsigned8bitvaluetype.*/ typedefunsignedshortuint2;/*Unsigned16bitvaluetype.*/ typedefunsignedlonguint4;/*Unsigned32bitvaluetype.*/ typedefsignedcharint1;/*Signed8bitvaluetype.*/ typedefsignedshortint2;/*Signed16bitvaluetype.*/ typedeflongintint4;/*Signed32bitvaluetype.*/ typedefsignedlongsint31;/*Signed32bitvalue*/ typedefsignedshortsint15;/*Signed16bitvalue*/ typedefsignedcharsint7;/*Signed8bitvalue*/ 3,得到指定地址上的一个字节或字 #defineMEM_B(x)(*((byte*)(x))) #defineMEM_W(x)(*((word*)(x))) 4,求最大值和最小值 #defineMAX(x,y)(((x)>(y))?(x):(y)) #defineMIN(x,y)(((x)<(y))?(x):(y)) 5,得到一个field在结构体(struct)中的偏移量 #defineFPOS(type,field)/ ((dword)&((type*)0)->field) 6,得到一个结构体中field所占用的字节数 #defineFSIZ(type,field)sizeof(((type*)0)->field) 7,按照LSB格式把两个字节转化为一个Word #defineFLIPW(ray)((((word)(ray)[0])*256)+(ray)[1]) 8,按照LSB格式把一个Word转化为两个字节 #defineFLOPW(ray,val)/ (ray)[0]=((val)/256);/ (ray)[1]=((val)&0xFF) 9,得到一个变量的地址(word宽度) #defineB_PTR(var)((byte*)(void*)&(var)) #defineW_PTR(var)((word*)(void*)&(var)) 10,得到一个字的高位和低位字节 #defineWORD_LO(xxx)((byte)((word)(xxx)&255)) #defineWORD_HI(xxx)((byte)((word)(xxx)>>8)) 11,返回一个比X大的最接近的8的倍数 #defineRND8(x)((((x)+7)/8)*8) 12,将一个字母转换为大写 #defineUPCASE(c)(((c)>=''a''&&(c)<=''z'')?((c)-0x20):(c)) 13,判断字符是不是10进值的数字 #defineDECCHK(c)((c)>=''0''&&(c)<=''9'') 14,判断字符是不是16进值的数字 #defineHEXCHK(c)(((c)>=''0''&&(c)<=''9'')||/ ((c)>=''A''&&(c)<=''F'')||/ ((c)>=''a''&&(c)<=''f'')) 15,防止溢出的一个方法 #defineINC_SAT(val)(val=((val)+1>(val))?(val)+1:(val)) 16,返回数组元素的个数 #defineARR_SIZE(a)(sizeof((a))/sizeof((a[0]))) 17,返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n) #defineMOD_BY_POWER_OF_TWO(val,mod_by)/ ((dword)(val)&(dword)((mod_by)-1)) 18,对于IO空间映射在存储空间的结构,输入输出处理 #defineinp(port)(*((volatilebyte*)(port))) #defineinpw(port)(*((volatileword*)(port))) #defineinpdw(port)(*((volatiledword*)(port))) #defineoutp(port,val)(*((volatilebyte*)(port))=((byte)(val))) #defineoutpw(port,val)(*((volatileword*)(port))=((word)(val))) #defineoutpdw(port,val)(*((volatiledword*)(port))=((dword)(val))) [2005-9-9添加] 19,使用一些宏跟踪调试 ANSI标准说明了五个预定义的宏名。它们是: _LINE_ _FILE_ _DATE_ _TIME_ _STDC_ 如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序 也许还提供其它预定义的宏名。 _LINE_及_FILE_宏指令在有关#line的部分中已讨论,这里讨论其余的宏名。 _DATE_宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。 源代码翻译到目标代码的时间作为串包含在_TIME_中。串形式为时:分:秒。 如果实现是标准的,则宏_STDC_含有十进制常量1。如果它含有任何其它数,则实现是 非标准的。 可以定义宏,例如: 当定义了_DEBUG,输出数据信息和所在文件所在行 #ifdef_DEBUG #defineDEBUGMSG(msg,date)printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_) #else #defineDEBUGMSG(msg,date) #endif 20,宏定义防止使用是错误 用小括号包含。 例如:#defineADD(a,b)(a+b) 用do{}while(0)语句包含多语句防止错误 例如:#difneDO(a,b)a+b;/ a++; 应用时:if(….) DO(a,b);//产生错误 else 解决方法:#difneDO(a,b)do{a+b;/ a++;}while(0)
宏中"#"和"##"的用法
一、一般用法 我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起. 用法: #include<cstdio> #include<climits> usingnamespacestd; #defineSTR(s)#s #defineCONS(a,b)int(a##e##b) intmain() { printf(STR(vck));//输出字符串"vck" printf("%d/n",CONS(2,3));//2e3输出:2000 return0; } 二、当宏参数是另一个宏的时候 需要注意的是凡宏定义里有用''#''或''##''的地方宏参数是不会再展开. 1,非''#''和''##''的情况 #defineTOW(2) #defineMUL(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,当有''#''或''##''的时候 #defineA(2) #defineSTR(s)#s #defineCONS(a,b)int(a##e##b) printf("intmax:%s/n",STR(INT_MAX));//INT_MAX#include<climits> 这行会被展开为: printf("intmax:%s/n","INT_MAX"); printf("%s/n",CONS(A,A));//compileerror 这一行则是: printf("%s/n",int(AeA)); INT_MAX和A都不会再被展开,然而解决这个问题的方法很简单.加多一层中间转换宏. 加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数. #defineA(2) #define_STR(s)#s #defineSTR(s)_STR(s)//转换宏 #define_CONS(a,b)int(a##e##b) #defineCONS(a,b)_CONS(a,b)//转换宏 printf("intmax:%s/n",STR(INT_MAX));//INT_MAX,int型的最大值,为一个变量#include<climits> 输出为:intmax: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)typevar##line #define__ANONYMOUS0(type,line)___ANONYMOUS1(type,_anonymous,line) #defineANONYMOUS(type)__ANONYMOUS0(type,__LINE__) 例:ANONYMOUS(staticint);即:staticint_anonymous70;70表示该行行号; 第一层:ANONYMOUS(staticint);-->__ANONYMOUS0(staticint,__LINE__); 第二层:-->___ANONYMOUS1(staticint,_anonymous,70); 第三层:-->staticint_anonymous70; 即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开; 2、填充结构 #defineFILL(a){a,#a} enumIDD{OPEN,CLOSE}; typedefstructMSG{ IDDid; constchar*msg; }MSG; MSG_msg[]={FILL(OPEN),FILL(CLOSE)}; 相当于: MSG_msg[]={{OPEN,"OPEN"}, {CLOSE,"CLOSE"}}; 3、记录文件名 #define_GET_FILE_NAME(f)#f #defineGET_FILE_NAME(f)_GET_FILE_NAME(f) staticcharFILE_NAME[]=GET_FILE_NAME(__FILE__); 4、得到一个数值类型所对应的字符串缓冲大小 #define_TYPE_BUF_SIZE(type)sizeof#type #defineTYPE_BUF_SIZE(type)_TYPE_BUF_SIZE(type) charbuf[TYPE_BUF_SIZE(INT_MAX)]; -->charbuf[_TYPE_BUF_SIZE(0x7fffffff)]; -->charbuf[sizeof"0x7fffffff"]; 这里相当于: charbuf[11]; |
本文地址:http://www.45fan.com/dnjc/69067.html