C宏——智者的利刃,愚者的惡夢(mèng)!
作者:乾坤一笑
本文出自 乾坤一笑 的Blog文章
水平不高不低的C++程序員最喜歡掛在嘴上的一句話(huà)就是:C宏,萬(wàn)惡之首,錯誤的開(kāi)端,應該被廢棄。
請注意,我用了一句不敬的修飾語(yǔ)“水平不高不低的”。為什么這么說(shuō)?因為水平低都插不上話(huà),都在在靜靜地聽(tīng)老前輩布道呢。水平高的,比如Bane Stroustrup老人家,也只是說(shuō)若干種場(chǎng)合下C++語(yǔ)言能夠提供比C macro更好的解決方案,而沒(méi)有完全否定C macro的價(jià)值。但是話(huà)就怕傳來(lái)傳去,一傳就走樣。久而久之,就被傳成上面那句話(huà)。其實(shí)說(shuō)來(lái)也很好笑:java程序員經(jīng)常說(shuō)java比C++好,說(shuō)C++手動(dòng)釋放內存老搞內存泄漏;C++程序員便反駁說(shuō),那是你水平低不會(huì )用。但是談到C宏,水平不高不低的C++程序員居然也走java的老路了——明明是自己不會(huì )用,自己知道的少,卻把責任推卸到C宏上。你自己笨我管不著(zhù),但是錯誤的言論如果誤導后人就不好了吧。:)
本文就舉幾個(gè)簡(jiǎn)單的使用C宏的例子,如果這些例子用C++不用宏的語(yǔ)法能更好的解決,那么你一定要回復blog告訴我,這樣下次我就不亂說(shuō)話(huà)了。否則,笑笑很生氣,后果很?chē)乐亍?)
例一、用C宏,書(shū)寫(xiě)代碼更簡(jiǎn)潔 這段代碼寫(xiě)網(wǎng)絡(luò )程序的朋友都很眼熟,是Net/3中mbuf的實(shí)現。
struct mbuf{ struct m_hdr mhdr; union { struct { struct pkthdr MH_pkthdr; /* M_PKTHDR set */ union { struct m_ext MH_ext; /* M_EXT set */ char MH_databuf[MHLEN]; } MH_dat; } MH; char M_databuf[MLEN]; /* !M_PKTHER, !M_EXT*/ } M_dat;}; 上面的代碼,假如我想訪(fǎng)問(wèn)最里層的MH_databuf,那么我必須寫(xiě)M_dat.MH.MH_dat.MH_databuf; 這是不是很長(cháng),很難寫(xiě)呀?這樣的代碼閱讀起來(lái)也不明了。其實(shí),對于MH_pkthdr、MH_ext、MH_databuf來(lái)說(shuō),雖然不是在一個(gè)結構層次上,但是如果我們站在mbuf之外來(lái)看,它們都是mbuf的屬性,完全可以壓扁到一個(gè)平面上去看。所以,源碼中有這么一組宏:#define m_next m_hdr.mh_next#define m_len m_hdr.mh_len#define m_data m_hdr.mh_data... ...#define m_pkthdr M_dat.MH.MH_pkthdr#define m_pktdat M_dat.MH.MH_dat.MH_databuf... ...這樣寫(xiě)起代碼來(lái),是不是很精練呢!
#ifndef _CRTAPI1#if _MSC_VER >= 800 && _M_IX86 >= 300#define _CRTAPI1 __cdecl#else /* _MSC_VER >= 800 && _M_IX86 >= 300 */#define _CRTAPI1#endif /* _MSC_VER >= 800 && _M_IX86 >= 300 */#endif /* _CRTAPI1 */#ifndef _SIZE_T_DEFINEDtypedef unsigned int size_t;#define _SIZE_T_DEFINED#endif /* _SIZE_T_DEFINED */#ifndef _MAC#ifndef _WCHAR_T_DEFINEDtypedef unsigned short wchar_t;#define _WCHAR_T_DEFINED#endif /* _WCHAR_T_DEFINED */#endif /* _MAC */ #ifndef _NLSCMP_DEFINED#define _NLSCMPERROR 2147483647 /* currently == INT_MAX */#define _NLSCMP_DEFINED#endif /* _NLSCMP_DEFINED */請問(wèn),這些指示宏如何取代呢?如果真的是沒(méi)有了這些宏,實(shí)現起來(lái)就更麻煩了吧。
ON_COMMAND(IDM_ABOUT, OnAbout)ON_COMMAND(IDM_FILENEW, OnFileNew)它是如何實(shí)現的IDM_ABOUT和OnAbout的關(guān)聯(lián)的呢?這要用到幾個(gè)宏。
#define DECLARE_MESSAGE_MAP() private: static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: static AFX_DATA const AFX_MSGMAP messageMap; virtual const AFX_MSGMAP* GetMessageMap() const; #define BEGIN_MESSAGE_MAP(theClass, baseClass) const AFX_MSGMAP* theClass::GetMessageMap() const { return &theClass::messageMap; } AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = { &baseClass::messageMap, &theClass::_messageEntries[0] }; AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = { #define ON_COMMAND(id, memberFxn) { WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn }, #define END_MESSAGE_MAP() {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } }; #define DECLARE_MESSAGE_MAP() private: static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: static AFX_DATA const AFX_MSGMAP messageMap; virtual const AFX_MSGMAP* GetMessageMap() const; #define BEGIN_MESSAGE_MAP(theClass, baseClass) const AFX_MSGMAP* theClass::GetMessageMap() const { return &theClass::messageMap; } AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = { &baseClass::messageMap, &theClass::_messageEntries[0] }; AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = { #define ON_COMMAND(id, memberFxn) { WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn }, #define END_MESSAGE_MAP() {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } }; 嘿嘿,就這么幾個(gè)宏,就構造出一個(gè)消息數組來(lái)。static unsigned short stopwatch[] = {0x07C6,0x1FF7,0x383B,0x600C,0x600C,0xC006,0xC006,0xDF06,0xC106,0xC106,0x610C,0x610C,0x3838,0x1FF0,0x07C0,0x0000}; 正如所看到的那樣,這些C語(yǔ)言常量并未有提供有關(guān)圖形實(shí)際模樣的任何線(xiàn)索。這里有一個(gè)驚人的#define定義的優(yōu)雅集合,允許程序建立常量使它們看上去像是屏幕上的圖形。#define X )*2+1#define _ )*2#define s ((((((((((((((((0 /* For building glyphs 16 bits wide */定義了它們之后,只要畫(huà)所需要的圖標或者圖形等,程序會(huì )自動(dòng)創(chuàng )建它們的十六進(jìn)制模式。使用這些宏定義,程序的自描述能力大大加強,上面這個(gè)例子可以轉變?yōu)椋?pre>static unsigned short stopwatch[] ={s _ _ _ _ _ X X X X X _ _ _ X X _ ,s _ _ _ X X X X X X X X X _ X X X ,s _ _ X X X _ _ _ _ _ X X X _ X X ,s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,s X X _ X X X X X _ _ _ _ _ X X _ ,s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,s _ _ X X X _ _ _ _ _ X X X _ _ _ ,s _ _ _ X X X X X X X X X _ _ _ _ ,s _ _ _ _ _ X X X X X _ _ _ _ _ _ ,s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _}; 顯然,與前面的代碼相比,它的意思更為明顯。標準的C語(yǔ)言具有八進(jìn)制、十進(jìn)制和十六進(jìn)制常量,但沒(méi)有二進(jìn)制常量,否則的話(huà)倒是一種更為簡(jiǎn)單的繪制圖形模式的方法。
聯(lián)系客服