瀏覽量:73次
從上一次寫文章到現(xiàn)在已經(jīng)快2個(gè)月了,為啥沒更新,因?yàn)樘α?
每天都在為了實(shí)現(xiàn)一些麻煩的功能而心急火燎,總是沒辦法靜下心來(lái)寫文章.所以一直拖延.
對(duì)于宏的一些個(gè)人用法其實(shí)早就想寫出來(lái)了,礙于時(shí)間關(guān)系一直拖到現(xiàn)在.
宏在很多人看來(lái)就是一個(gè)危險(xiǎn)的存在.不過在我看來(lái)宏真的是一個(gè)不可或缺的好東西.之所以被嗤之以鼻,那是有很多人不會(huì)正確使用宏,導(dǎo)致項(xiàng)目中宏定義亂飛,各種難以理解的宏嵌套,宏展開編譯失敗的復(fù)雜提示信息.
1.標(biāo)識(shí)當(dāng)前平臺(tái).
因?yàn)槲业捻?xiàng)目需要在windows和linux都要能正常運(yùn)行,我在windows進(jìn)行開發(fā),linux上運(yùn)行.我只是不喜歡在linux上寫代碼而已,用慣了windows的vs,不太愿意再花太多功夫去習(xí)慣別的系統(tǒng).而且是linux這樣的對(duì)新手不友好的系統(tǒng).
先顯式定義三個(gè)平臺(tái)標(biāo)識(shí)宏
#definePLATFORM_WINDOWS0#definePLATFORM_LINUX1#definePLATFORM_ANDROIDPLATFORM_LINUX//正在運(yùn)行的平臺(tái)標(biāo)識(shí)#ifdefWINDOWS#defineRUN_PLATFORMPLATFORM_WINDOWS#endif#ifdefLINUX#defineRUN_PLATFORMPLATFORM_LINUX#endif#ifndefRUN_PLATFORM#defineRUN_PLATFORM-1#error"wrongplatform!"#endif因?yàn)橛行╊^文件只有windows有,有些頭文件只有l(wèi)inux才有,所以就會(huì)這樣寫
#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#endif2.統(tǒng)一windows和linux的部分操作
因?yàn)楹芏鄸|西在windows和linux上的類型定義是不同的,但是用法大體是一樣的,所以為了方便,就用宏統(tǒng)一起來(lái).
#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其實(shí)也就是線程,socket,sprintf的用法統(tǒng)一.
3.一些簡(jiǎn)單函數(shù)的宏,用于提高效率
這類宏其實(shí)主要的還是為了效率考慮,一些函數(shù)本身就是為了高效運(yùn)行而存在的,如果再因?yàn)檎{(diào)用函數(shù)而有一些性能上的損失,真是有點(diǎn)太可惜了.
雖然內(nèi)聯(lián)可以達(dá)到同樣的效果.但是是否真的內(nèi)聯(lián)了,還得看編譯器實(shí)現(xiàn),并不是定義放到頭文件就是內(nèi)聯(lián).我也沒有去測(cè)試到底怎么樣才能保證真的內(nèi)聯(lián).實(shí)在是沒有多余的時(shí)間花在這上面了.所以為了保證沒有函數(shù)調(diào)用的開銷,用宏還是最保險(xiǎn)的.
//設(shè)置value的指定位置pos的字節(jié)的值為byte,并且不影響其他字節(jié)#defineSET_BYTE(value,b,pos)value=(value&~(0x000000FF<<(8*pos)))|(b<<(8*pos))//獲得value的指定位置pos的字節(jié)的值#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.z4.一些只能使用宏來(lái)實(shí)現(xiàn)的功能
比如獲取當(dāng)前行號(hào),當(dāng)然,這是自帶的一個(gè)宏,可以獲取當(dāng)前行號(hào),類型是整數(shù),只是我這里使用#將其轉(zhuǎn)換為了一個(gè)字符串,因?yàn)楹暾归_也是有順序的,所以這里只能定義兩個(gè)宏來(lái)將__LINE__轉(zhuǎn)換為字符串.
#defineSTR(t)#t#defineLINE_STR(v)STR(v)#define_FILE_LINE_"File:"string(__FILE__)",Line:"LINE_STR(__LINE__)5.簡(jiǎn)單替換
這也許就是宏最簡(jiǎn)單的用法了,只是單純的替換文本.
#defineFOR_I(count)for(uinti=0;i整數(shù)轉(zhuǎn)字符串,避免使用堆內(nèi)存,只使用棧內(nèi)存,安全而且高效.
6.第4條和第5條的結(jié)合,目的還是簡(jiǎn)化代碼
第4條中用到了#用于將宏參數(shù)轉(zhuǎn)換為字符串,其他的還有##用于連接文本,__ARGS__用于獲取宏參數(shù)中的可變參數(shù)列表
//用于遍歷stl容器,要在循環(huán)結(jié)束后添加END#defineFOREACH(iter,stl)\autoiter=stl.begin();\autoiter##End=stl.end();\FOR(stl,;iter!=iter##End;iter)//不帶內(nèi)存合法檢測(cè)的常規(guī)內(nèi)存申請(qǐng)#defineNORMAL_NEW(className,ptr,...)\NULL;\ptr=newclassName(__VA_ARGS__);\if(ptr==NULL)\{\ERROR(string("cannotallocmemory!")"className:"STR(className));\}//生成靜態(tài)字符串常量的名字#defineNAME(name)STR_##name//聲明一個(gè)靜態(tài)字符串常量#defineDECLARE_STRING(name)staticconstchar*NAME(name)//定義一個(gè)靜態(tài)字符串常量#defineDEFINE_STRING(name)constchar*StringDefine::NAME(name)=STR(name)//創(chuàng)建一個(gè)消息對(duì)象#definePACKET(classType,packet)classType*packet=mNetServer->createPacket(packet,NAME(classType))基本也就以上這些了,總之就是用來(lái)簡(jiǎn)化代碼,提高運(yùn)行效率,實(shí)現(xiàn)一些常規(guī)函數(shù)無(wú)法實(shí)現(xiàn)的功能.總的來(lái)說,我還是比較喜歡宏的.
[聲明]本網(wǎng)轉(zhuǎn)載網(wǎng)絡(luò)媒體稿件是為了傳播更多的信息,此類稿件不代表本網(wǎng)觀點(diǎn),本網(wǎng)不承擔(dān)此類稿件侵權(quán)行為的連帶責(zé)任。故此,如果您發(fā)現(xiàn)本網(wǎng)站的內(nèi)容侵犯了您的版權(quán),請(qǐng)您的相關(guān)內(nèi)容發(fā)至此郵箱【779898168@qq.com】,我們?cè)诖_認(rèn)后,會(huì)立即刪除,保證您的版權(quán)。
官網(wǎng)優(yōu)化
整站優(yōu)化
渠道代理
400-655-5776