C語言的通用鏈表

來源:互聯網
上載者:User

標籤:c語言   通用   鏈表   資料結構   核心   

在作業系統編程中, 往往是使用C語言, 但C使用起來極為痛苦, 不像C++有方便的STL模板庫使用。

linux核心中,有一套非常神奇的通用鏈表結構,能夠方便的使用,管理各種類型的資料,我們今天就來研究一下,核心中的C資料結構。

本文參考:【深入分析 Linux 核心鏈表】

首先,我們的目標是構建一個迴圈雙鏈表結構,為何是雙鏈表,還要迴圈,當然是從易用性考慮了,雙鏈表能夠方便的得知自己的上一個元素,在核心中管理資料更為方便。

其一般結構大概是這樣:

實現機制

首先定義一個list_node結構,用來儲存鏈表節點資訊:

    /**     * @brief 鏈表節點結構     */    typedef struct _list_node    {        struct _list_node   *next;        struct _list_node   *prev;    } list_node;

然後用一個存放資料的結構,比如我們要用int型的鏈表,如下定義:

    /**     * @brief 資料存放結構     */    typedef struct _Int_List    {        list_node   node;        int         data;    } Int_List;

這和我們傳統的鏈表實現思路好像不大一樣,我們經典的C語言鏈表當然是在鏈表中儲存資料:

    /**     * @brief 鏈表節點結構     */    typedef ElementType     int;    typedef struct _list_node    {        struct _list_node   *next;        struct _list_node   *prev;        ElementType         data;    } list_node;

但這樣的實現必然會造成鏈表結構被反覆定義,難以實現泛型。另外一種思路可能是將ElementType實現成void*指標,然後在使用時進行強制類型轉換,但這樣必然會帶來反覆的類型轉換,而且其使用相對不便。

這時要出問題了,如果資料在外層,鏈表在裡層,那麼如何從鏈表找到資料呢?

offsetof宏和container_of宏

為了實現從內層元素找外層元素的功能,我們需要用到這兩個系統宏,一眼看上去很複雜,但實際上並不難理解。

/** * @brief 確定當前成員變數,在結構體中位移量的宏 */#ifndef offsetof#define offsetof(type, member) ((size_t) &((type*)0)->member)#endif
/** * @brief 根據成員變數,找包含他的結構體指標 */#ifndef container_of#define container_of(ptr, type, member) ({  \    const typeof( ((type *)0)->member ) *__mptr = (ptr);     (type *)( (char *)__mptr - offsetof(type,member) );})#endif

這兩個宏較為複雜,首先是offsetof宏,這個宏用0號指標去尋找成員變數,我們試想,如何是普通的一個結構體,C編譯器如何尋找其一個成員呢?
例如:

    /**     * @brief 資料存放結構     */    typedef struct _Int_List    {        list_node   node;        int         data;    } Int_List;

假設我們用Int_List A語句,執行個體化一個結構體,然後取到了A的地址0x00001000
那麼node的起始地址是不是也是0x00001000
data的起始地址是不是0x00001000+data的位移量?

那麼如何我想求data的位移量,不就是如下的代碼麼:

    (&A)->data - (&A);

如果A的地址為0時,那麼也就不用減了,就是我們宏定義中的用法。

而container_of宏也是採用類似的思路,既然找到了當前list_node成員的位移量,那麼減去位移量,便是外層包圍著的結構體的起始地址。

那好,這樣我們就能實現這個鏈表了,但其實也不用這樣費事,還有簡單的辦法,那就是讓我們的被包含的list_node成員結構,處於我們資料存放區結構的第一個位置,那麼其地址就是包圍其結構的地址,直接類型轉換即可。

這種思路實際上也被用於C語言的繼承機制的實現。

Github項目

到此,我們已經講解了通用鏈表的實現思路,大家可以嘗試自己實現一個獨特的通用鏈表,具體內容就不一一贅述,我將完整的工程已經發布到了Github上面,歡迎大家前來fork測試。
【Clist項目地址】

本人才疏學淺,如有疏漏,還望指正。

C語言的通用鏈表

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.