建站优化

当前位置:

c++宏定义用法,c++ 宏定义

浏览量:118次

c++宏定义用法,c++ 宏定义

从上一次写文章到现在已经快2个月了,为啥没更新,因为太忙了!

每天都在为了实现一些麻烦的功能而心急火燎,总是没办法静下心来写文章.所以一直拖延.

对于宏的一些个人用法其实早就想写出来了,碍于时间关系一直拖到现在.

宏在很多人看来就是一个危险的存在.不过在我看来宏真的是一个不可或缺的好东西.之所以被嗤之以鼻,那是有很多人不会正确使用宏,导致项目中宏定义乱飞,各种难以理解的宏嵌套,宏展开编译失败的复杂提示信息.

1.标识当前平台.

因为我的项目需要在windows和linux都要能正常运行,我在windows进行开发,linux上运行.我只是不喜欢在linux上写代码而已,用惯了windows的vs,不太愿意再花太多功夫去习惯别的系统.而且是linux这样的对新手不友好的系统.

先显式定义三个平台标识宏

#definePLATFORM_WINDOWS0#definePLATFORM_LINUX1#definePLATFORM_ANDROIDPLATFORM_LINUX//正在运行的平台标识#ifdefWINDOWS#defineRUN_PLATFORMPLATFORM_WINDOWS#endif#ifdefLINUX#defineRUN_PLATFORMPLATFORM_LINUX#endif#ifndefRUN_PLATFORM#defineRUN_PLATFORM-1#error"wrongplatform!"#endif

因为有些头文件只有windows有,有些头文件只有linux才有,所以就会这样写

#ifRUN_PLATFORM==PLATFORM_WINDOWS#include#include#include#include#include#include#include#include#endif#ifRUN_PLATFORM==PLATFORM_LINUX#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#endif

2.统一windows和linux的部分操作

因为很多东西在windows和linux上的类型定义是不同的,但是用法大体是一样的,所以为了方便,就用宏统一起来.

#ifRUN_PLATFORM==PLATFORM_WINDOWS#defineMY_THREADHANDLE#defineMY_SOCKETSOCKET#defineNULL_THREADNULL#defineTHREAD_CALLBACK_DECLEAR(func)staticDWORDWINAPIfunc(LPVOIDargs)#defineTHREAD_CALLBACK(class,func)DWORDWINAPIclass##::##func(LPVOIDargs)#defineCREATE_THREAD(thread,func,args)thread=CreateThread(NULL,0,func,args,0,NULL)#defineCLOSE_THREAD(thread)\if(thread!=NULL_THREAD)\{\TerminateThread(thread,0);\CloseHandle(thread);\thread=NULL_THREAD;\}#defineCLOSE_SOCKET(socket)closesocket(socket);#defineCLASS_NAME(T)string(typeid(T).name()).substr(strlen("class"))#defineSPRINTF(buffer,bufferSize,...)sprintf_s(buffer,bufferSize,__VA_ARGS__)#elifRUN_PLATFORM==PLATFORM_LINUX#defineMY_THREADpthread_t#defineMY_SOCKETunsignedint#defineNULL_THREAD0#defineSOCKADDR_INsockaddr_in#defineTHREAD_CALLBACK_DECLEAR(func)staticvoid*func(void*args)#defineTHREAD_CALLBACK(class,func)void*class##::##func(void*args)#defineCREATE_THREAD(thread,func,args)pthread_create(&thread,NULL,func,args)#defineCLOSE_THREAD(thread)\if(thread!=NULL_THREAD)\{\pthread_cancel(thread);\thread=NULL_THREAD;\}#defineCLOSE_SOCKET(socket)close(socket);#defineCLASS_NAME(T)removePreNumber(typeid(T).name())#defineSPRINTF(buffer,bufferSize,...)sprintf(buffer,__VA_ARGS__)#endif

其实也就是线程,socket,sprintf的用法统一.

3.一些简单函数的宏,用于提高效率

这类宏其实主要的还是为了效率考虑,一些函数本身就是为了高效运行而存在的,如果再因为调用函数而有一些性能上的损失,真是有点太可惜了.

虽然内联可以达到同样的效果.但是是否真的内联了,还得看编译器实现,并不是定义放到头文件就是内联.我也没有去测试到底怎么样才能保证真的内联.实在是没有多余的时间花在这上面了.所以为了保证没有函数调用的开销,用宏还是最保险的.

//设置value的指定位置pos的字节的值为byte,并且不影响其他字节#defineSET_BYTE(value,b,pos)value=(value&~(0x000000FF<<(8*pos)))|(b<<(8*pos))//获得value的指定位置pos的字节的值#defineGET_BYTE(value,pos)(value&(0x000000FF>(8*pos)#defineGET_BIT(value,pos)(((value&(1>(pos))&1)#defineSET_BIT(value,pos,bit)value=value&~(1<<(pos))|((bit)=-MathUtility::MIN_DELTA&&value<=MathUtility::MIN_DELTA)#defineIS_FLOAT_EQUAL(value1,value2)(IS_FLOAT_ZERO(value1-value2))#defineIS_VECTOR3_EQUAL(vec0,vec1)(IS_FLOAT_ZERO(vec0.x-vec1.x)&&IS_FLOAT_ZERO(vec0.y-vec1.y)&&IS_FLOAT_ZERO(vec0.z-vec1.z))#defineIS_VECTOR2_EQUAL(vec0,vec1)(IS_FLOAT_ZERO(vec0.x-vec1.x)&&IS_FLOAT_ZERO(vec0.y-vec1.y))#defineLENGTH_XY(x,y)sqrt(x*xy*y)#defineLENGTH_XYZ(x,y,z)sqrt(x*xy*yz*z)#defineLENGTH_2(vec)sqrt(vec.x*vec.xvec.y*vec.y)#defineLENGTH_3(vec)sqrt(vec.x*vec.xvec.y*vec.yvec.z*vec.z)#defineSQUARED_LENGTH_XY(x,y)(x*xy*y)#defineSQUARED_LENGTH_XYZ(x,y,z)(x*xy*yz*z)#defineSQUARED_LENGTH_2(vec)(vec.x*vec.xvec.y*vec.y)#defineSQUARED_LENGTH_3(vec)(vec.x*vec.xvec.y*vec.yvec.z*vec.z)#defineLENGTH_LESS_3(vec,length)(vec.x*vec.xvec.y*vec.yvec.z*vec.zlength*length)#defineDOT_3(v0,v1)(v0.x*v1.xv0.y*v1.yv0.z*v1.z)#defineDOT_2(v0,v1)(v0.x*v1.xv0.y*v1.y)#defineCROSS(v0,v1)Vector3(v1.y*v0.z-v0.y*v1.z,v1.x*v0.z-v0.x*v1.z,v1.x*v0.y-v0.x*v1.y)#defineCLAMP(value,minValue,maxValue)\{\if(value>maxValue){value=maxValue;}\elseif(valuemaxValue){value=maxValue;}#defineCLAMP_CYCLE(value,minValue,maxValue,cycle)\while(valuemaxValue)\{\value-=cycle;\}#defineCLAMP_ANGLE(angle,minValue,maxValue,pi)CLAMP_CYCLE(angle,minValue,maxValue,pi*2.0f)#defineCLAMP_RADIAN_180(radian)CLAMP_ANGLE(radian,-MathUtility::MATH_PI,MathUtility::MATH_PI,MathUtility::MATH_PI)#defineCLAMP_DEGREE_180(degree)CLAMP_ANGLE(degree,-180.0f,180.0f,180.0f);#defineCLAMP_RADIAN_360(radian)CLAMP_ANGLE(radian,0.0f,MathUtility::MATH_PI*2.0f,MathUtility::MATH_PI)#defineCLAMP_DEGREE_360(degree)CLAMP_ANGLE(degree,0.0f,360.0f,180.0f)#defineTO_DEGREE(radian)(radian*MathUtility::Rad2Deg)#defineTO_RADIAN(degree)(degree*MathUtility::Deg2Rad)#defineSATURATE(value)CLAMP(value,0.0f,1.0f)//判断value是否在minRange和maxRange之间,并且minRange和maxRange的顺序不固定#defineIS_IN_RANGE(value,minRange,maxRange)(value>=MIN(minRange,maxRange)&&value=minRange&&value<=maxRange)#defineIS_VECTOR2_IN_RANGE(value,minRange,maxRange)(IS_IN_RANGE(value.x,minRange.x,maxRange.x)&&IS_IN_RANGE(value.y,minRange.y,maxRange.y))#defineIS_VECTOR2_IN_RANGE_FIXED(value,minRange,maxRange)(IS_IN_RANGE_FIXED(value.x,minRange.x,maxRange.x)&&IS_IN_RANGE_FIXED(value.y,minRange.y,maxRange.y))#defineMIN(value0,value1)(value0value1?value0:value1)#defineINVERSE_LERP(a,b,value)((value-a)/(b-a))#defineLERP_SIMPLE(start,end,t)(start(end-start)*t)#defineABS(value)value=value>0?value:-value;#defineSIGN(sign,value)\if(value>0){sign=1;}\elseif(value<0){sign=-1;}\else{sign=0;}#defineSWAP(value0,value1)\auto&temp=value0;\value0=value1;\value1=temp;#defineCEIL(value)((int)(value)>=0.0f&&value>(int)(value))?(int)(value)1:(int)(value)#defineCEIL_2(vec)\vec.x=(float)(CEIL(vec.x));\vec.y=(float)(CEIL(vec.y));#defineCEIL_3(vec)\vec.x=(float)(CEIL(vec.x));\vec.y=(float)(CEIL(vec.y));\vec.z=(float)(CEIL(vec.z));

4.一些只能使用宏来实现的功能

比如获取当前行号,当然,这是自带的一个宏,可以获取当前行号,类型是整数,只是我这里使用#将其转换为了一个字符串,因为宏展开也是有顺序的,所以这里只能定义两个宏来将__LINE__转换为字符串.

#defineSTR(t)#t#defineLINE_STR(v)STR(v)#define_FILE_LINE_"File:"string(__FILE__)",Line:"LINE_STR(__LINE__)

5.简单替换

这也许就是宏最简单的用法了,只是单纯的替换文本.

#defineFOR_I(count)for(uinti=0;i比如for循环这种东西写多了也觉得厌烦了,所以就稍微简化了一些

整数转字符串,避免使用堆内存,只使用栈内存,安全而且高效.

6.第4条和第5条的结合,目的还是简化代码

第4条中用到了#用于将宏参数转换为字符串,其他的还有##用于连接文本,__ARGS__用于获取宏参数中的可变参数列表

//用于遍历stl容器,要在循环结束后添加END#defineFOREACH(iter,stl)\autoiter=stl.begin();\autoiter##End=stl.end();\FOR(stl,;iter!=iter##End;iter)//不带内存合法检测的常规内存申请#defineNORMAL_NEW(className,ptr,...)\NULL;\ptr=newclassName(__VA_ARGS__);\if(ptr==NULL)\{\ERROR(string("cannotallocmemory!")"className:"STR(className));\}//生成静态字符串常量的名字#defineNAME(name)STR_##name//声明一个静态字符串常量#defineDECLARE_STRING(name)staticconstchar*NAME(name)//定义一个静态字符串常量#defineDEFINE_STRING(name)constchar*StringDefine::NAME(name)=STR(name)//创建一个消息对象#definePACKET(classType,packet)classType*packet=mNetServer->createPacket(packet,NAME(classType))

基本也就以上这些了,总之就是用来简化代码,提高运行效率,实现一些常规函数无法实现的功能.总的来说,我还是比较喜欢宏的.

[声明]本网转载网络媒体稿件是为了传播更多的信息,此类稿件不代表本网观点,本网不承担此类稿件侵权行为的连带责任。故此,如果您发现本网站的内容侵犯了您的版权,请您的相关内容发至此邮箱【779898168@qq.com】,我们在确认后,会立即删除,保证您的版权。