複雜結構體的存取器 [C宏——智者的利刃,愚者的惡夢]

C宏——智者的利刃,愚者的惡夢!html

在《C宏——智者的利刃,愚者的惡夢! 》一文中,提到了一種使用宏的方式 —— 「例1、用C宏,書寫代碼更簡潔」。
《C宏——智者的利刃,愚者的惡夢! 》: http://www.vckbase.com/document/viewdoc/?id=1454
《C宏——智者的利刃,愚者的惡夢! 》: http://blog.vckbase.com/smileonce/archive/2005/03/27/4081.html

本文章分別給出C++和C中不使用宏的實現方式。linux

 

首先,書寫代碼更簡潔是不是優勢?
有興趣的讀者請看看《設計Qt風格的C++API》一文中「便利陷阱」 (The Convenience Trap) 一節。
中文: http://blog.csdn.net/TopLanguage/archive/2008/02/21/2111467.aspx
英文: http://doc.trolltech.com/qq/qq13-apis.html程序員

【永遠記住代碼一次寫就,以後須要不斷的閱讀並理解。】
【Keep in mind that code is written more than once but has to be understood over and over again.】api

 

若是真要達到笑笑文中——【mbuf的屬性,徹底能夠壓扁到一個平面上去看】——這個目的,除了宏,也是有其餘方法的。函數

在這裏說明一下,笑笑在文中並無給出struct mbuf的完整定義。
我沒有linux,Cygwin也刪掉了,安裝挺麻煩的……
順藤摸瓜的下載了一部分文件:
http://opengrok.creo.hu/dragonfly/xref/src/sys/sys/mbuf.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/sys/param.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/net/netisr.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/net/netmsg.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/sys/thread.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/sys/msgport.h
企圖拼出一個完整的struct mbuf定義,但實在太麻煩,這裏就放棄了 ……學習

因此只用一個簡單的例子來講明如何不使用宏來達到這一目的。
固然,也會說明若是結構體更復雜該如何擴展。測試

 


/** structure definition */

/* simple Point & Size structure */
typedef 
struct Point_ {
    
int x;
    
int y;
}
 Point;

typedef 
struct Size_ {
    
int width;
    
int height;
}
 Size;

/** complex Rect structrue */
typedef 
struct Rect_ {
    Point offset;
    Size size;
}
 Rect;

 


C++方案:

 


namespace cpp {

    
class RectAccessor {
    
public:
        RectAccessor(Rect
& r)
            :x(r.offset.x)
            ,y(r.offset.y)
            ,width(r.size.width)
            ,height(r.size.width)
        
{  }
    
public:
        
int& x;
        
int& y;
        
int& width;
        
int& height;
    }
;

    
void test(int (&arr)[4],Rect* r) {
        RectAccessor ac(
*r);
        
// 同一平面
        ac.x = arr[0];
        ac.y 
= arr[1];
        ac.width 
= arr[2];
        ac.height 
= arr[3];
        printf(
"%d %d %d %d\n",ac.x,ac.y,ac.width,ac.height);
    }

}


const怎麼辦?
(對const的考慮,C++程序員老是比C程序員要多一點,不是嗎?)優化


/** const accessor */
// 再定義一個const存取器不就完了?
class ConstRectAccessor /**/ };

//若是以爲這樣名字不統一,很差看,也能夠這樣
template<bool is_constant>
class RectAccessor;
template
<>
class RectAccessor<false> /* 同上面那個RectAccessor */ };
class RectAccessor<true> /* 同上面那個ConstRectAccessor */ };


對更復雜的結構體,該方法的擴展是很容易的事情:在構造函數的成員初始化列表裏寫就是了。spa


C呢?是否是隻能使用宏?固然不是。
C的方案:

 


namespace c {

    typedef union RectAccessor_
    
{
        
struct S1 {
            
int x;
            
int y;
            
int width;
            
int height;
        }
;
        
struct S2 {
            Point offset;
            Size size;
        }
;
        Rect rect;

    }
 RectAccessor;

    __declspec(noinline) 
void test(int (&arr)[4],Rect* r) {
        RectAccessor
* ac = (RectAccessor*) r;
        
// 同一平面
        ac->= arr[0];
        ac
->= arr[1];
        ac
->width = arr[2];
        ac
->height = arr[3];
        printf(
"%d %d %d %d\n",ac->x,ac->y,ac->width,ac->height);
    }

}


對const, 轉型的時候,注意使用合適的指針類型就能夠了。.net

想更復雜的結構體擴展:
若是對上面的方案不理解,甚至對mbuf都不理解,最好仍是老老實實的使用全名。
永遠記得,代碼讀的次數比寫的次數多!

上面的方案,是利用了一個特性,叫「匿名聯合」還別的什麼東東。
含義大概是這樣:


union U {
  
struct /*anonymous */ {
     t11 v11;
     t12 v12;
     
/* more members */
  }
 /*anonymous */;
  
struct /*anonymous */ {
     t21 v21;
     t22 v22;
     
/* more members */
  }
 /*anonymous */;
  
/** more structures */
}
;

/* 那麼就能夠*/
U u;
u.v11; u.v12; u.v21;

 


經測試,上面兩種方案,在VC8 O2優化下,生成的機器碼同不使用Accessor 徹底一致
GCC就沒有測試了,看不懂它的彙編……

 

對宏的方案(也就是mbuf.h中提供的)的改進:
簡直沒法想象!竟然在 頭文件定義如此 廣泛小寫 名字!

 


/** mbuf_accessor_define.h */
#define    m_next        m_hdr.mh_next
#define    m_len        m_hdr.mh_len
#define    m_data        m_hdr.mh_data
#define    m_type        m_hdr.mh_type
#define    m_flags        m_hdr.mh_flags
#define    m_nextpkt    m_hdr.mh_nextpkt
#define    m_pkthdr    M_dat.MH.MH_pkthdr
#define    m_ext        M_dat.MH.MH_dat.MH_ext
#define    m_pktdat    M_dat.MH.MH_dat.MH_databuf
#define    m_dat        M_dat.M_databuf

/** mbuf_accessor_undef.h */
#undef    m_next
#undef    m_len
#undef    m_data
#undef    m_type
#undef    m_flags
#undef    m_nextpkt
#undef    m_pkthdr
#undef    m_ext
#undef    m_pktdat
#undef    m_dat

/* 須要的時候 */
#include 
<mbuf_accessor_define.h>
/* 使用簡寫 */
/* 使用簡寫 */
/* 使用簡寫 */
/* 而後馬上取消定義 */
#include 
<mbuf_accessor_undef.h>

 


PS:C程序員總說C++的語言特性有心智包袱,難道宏就不算心智包袱?

 

物理老師歷來都是這麼寫:              F = M*A;
沒見任何一個物理老師會這麼寫:  F = multiply(M,A);
若是是,請馬上和同窗打賭說他是程序員,並且頗有多是C程序員。

hp_int i1,i2,i3;
// ...
數學老師也老是這麼寫: hp_int icpp = i1 + i2 * i3;

不會有數學老師這麼寫:
hp_int ic;
hp_assign(&i2,&ic);
hp_multiply(&i3,&ic);
hp_plus(&i1,&ic);

或者這麼寫:
hp_plus(&i1,hp_multiply(&i3,hp_assgin(&i2,&ic) ) );

(hp —— 高精度,  對矩陣也是一樣)


C程序員說,不知道 string s = s1 + s2 + s3;背後作了什麼。
C++程序員說,由庫決定。
C程序員說,我對庫中那些精巧的技術不感興趣(不熟悉,不肯意學)。
C++程序員說,就對宏技術感興趣?
C程序員說,宏效率高。
C++程序員說, 若是 string s = s1 + s2 + s3;能夠實現得比 strcat(strcat(strcat(....) 效率更高,你信不信?
C++ 程序員再說,若是能夠天然的寫出hp_int icpp = i1 + i2 * i3;有正確的運算優先級,效率與 hp_plus(&i1,hp_multiply(&i3,hp_assgin(&i2,&ic) ) );等同,你還願意用後者?
C程序員說,那些實現都是心智包袱,我不喜歡。
C++程序員說,宏算不算心智包袱?你怎麼就喜歡了?

總之,這只是一種不肯學習的心態,一種手拿錘子見什麼都是釘子的心態。 Linus年紀也不算大……才40歲…… 哎……

相關文章
相關標籤/搜索